Compare commits

...

886 Commits
3.2.4 ... 6.0.5

Author SHA1 Message Date
Luke D. Jones
ccf8d8df91 Prep 6.0.5 version 2024-05-10 12:44:46 +12:00
Luke D. Jones
b970d364f7 Fix test 2024-05-10 12:36:34 +12:00
Luke D. Jones
1da68ea69d Try to mitigate the lack of kbd_brightness on some laptops 2024-05-10 12:22:36 +12:00
Luke D. Jones
e62e7e8eca Cleanup sys config 2024-05-10 10:26:32 +12:00
Luke D. Jones
1b1d10c461 Try to better handle pre-2021 laptops with lightbar 2024-05-10 10:04:51 +12:00
Stefan Boca
14ea0f6d83 Update GA402XV supported aura modes 2024-05-08 19:20:17 -07:00
Luke Jones
5107a6c39c Merge branch 'FAYZER77-main-patch-34823' into 'main'
Change 733C model profile to add support for Lid LED, and remove unneeded basic zones entries

See merge request asus-linux/asusctl!183
2024-05-08 23:12:56 +00:00
FAYZER77
2c77ec9e24 Change 733C model profile to add support for Lid LED, and remove unneeded basic zones entries 2024-05-08 23:08:19 +00:00
Luke D. Jones
817a66bdf1 Prep 6.0.4 2024-05-09 11:00:51 +12:00
Luke D. Jones
664a3d5533 Match G533Q to 0x8166 keyboard ID explicitly
Should close #438
2024-05-09 10:01:48 +12:00
Luke D. Jones
37bc5e45b9 Fix: ensure property derive is on all property methods for slash 2024-05-09 09:34:02 +12:00
Luke D. Jones
a18692ef1e Fix up colour sliders
- Fixup colour sliders for UI
- Correctly drop tokio runtime
2024-05-08 22:55:11 +12:00
Luke D. Jones
1b023d0f5f Fix and prep new 6.0.2 release 2024-05-08 16:27:40 +12:00
Luke D. Jones
74f74e73c4 Update deps, point release 2024-05-07 13:56:25 +12:00
Luke D. Jones
9c7df9ad39 Update deps, point release 2024-05-07 12:58:17 +12:00
Luke D. Jones
94adf5d24d Revert back to zbus 4.1 2024-05-06 23:54:36 +12:00
Luke D. Jones
8dbdb68175 Increase tray icon sleep time 2024-05-06 23:14:51 +12:00
Luke D. Jones
89002eb5ec Use fluent-dark instead of cosmic due to compile times 2024-05-06 23:01:03 +12:00
Luke D. Jones
dc9ef8cf54 Remove unused deps 2024-05-06 13:25:07 +12:00
Luke D. Jones
667697d042 Cleanup deps 2024-05-06 10:58:11 +12:00
Luke D. Jones
bc92fa11f9 Update all cargo.toml. Support G713P 2024-05-06 09:45:35 +12:00
Luke D. Jones
f5d5681b49 Prep changelog 2024-05-05 20:52:38 +12:00
Luke D. Jones
1c8e50843b Cleanup files, prep new release 2024-05-05 20:22:56 +12:00
Luke D. Jones
487d140bd5 Anime: Better prevent await blocking. Prevent Slash taking over anime USB dev 2024-05-05 10:56:55 +12:00
Luke D. Jones
661ea8d3bf Fix fedora install instruction 2024-04-19 11:11:58 +12:00
Luke D. Jones
28d1ed6ab3 Fix broke logix 2024-04-18 14:40:39 +12:00
Luke D. Jones
903b978e86 Add missing files 2024-04-18 13:55:02 +12:00
Luke D. Jones
519f6bd46b Cleanup notifs, sys state, ac/bat commands 2024-04-18 13:48:23 +12:00
Luke D. Jones
a94a8ca28d Support the GU605M keyboard 2024-04-18 10:08:40 +12:00
Luke D. Jones
f9dca2da5d Re-add TUF keyboard support 2024-04-17 21:39:58 +12:00
Luke Jones
df88ff1acb Update asusd.service 2024-04-17 06:11:00 +00:00
Luke Jones
cb5aa0f170 Update asusd.service 2024-04-17 06:10:44 +00:00
Luke D. Jones
4ea79f966e Add updated translation + aura_support.ron 2024-04-17 14:18:27 +12:00
Luke D. Jones
b8bc1a01b3 Fix colour hex in gui 2024-04-17 12:46:36 +12:00
Luke D. Jones
0e5d1815bd Bump alpha version 2024-04-17 11:55:19 +12:00
Luke D. Jones
64e8cb65d0 Many cleanup and fix 2024-04-17 11:54:14 +12:00
Luke D. Jones
3142353f98 Fix tests 2024-04-11 13:18:03 +12:00
Luke D. Jones
484ca692ad Refactoring led support data 2024-04-10 21:14:47 +12:00
Luke D. Jones
1ebdfada96 Update discord invite 2024-04-10 18:09:41 +12:00
Luke D. Jones
3bc9dfcda1 Support GA402N keyboard 2024-04-10 17:04:21 +12:00
Luke D. Jones
895e5d2ca3 Support GA402N keyboard 2024-04-10 17:04:08 +12:00
Luke D. Jones
564992719e Fixes to slash merge 2024-04-10 09:13:26 +12:00
Luke Jones
a737d240be Merge pull request #23 from jschoubben/main
Add support for 2024 G14 Slash lighting (GA403UI)
2024-04-10 08:55:17 +12:00
Luke Jones
d89c1ebf26 Merge branch 'main' into main 2024-04-10 08:54:54 +12:00
Luke D. Jones
be7686bb46 Dump deps and version 2024-04-09 21:24:55 +12:00
Luke D. Jones
4f70055f85 Complete building 2024-04-09 21:02:09 +12:00
Luke D. Jones
91ca049298 Unify the laptop aura power stuff 2024-04-09 12:13:42 +12:00
Luke D. Jones
635d0378ac Bump deps 2024-04-06 14:10:18 +13:00
Luke D. Jones
1c729316f7 Refactor, rename, organise rog-aura stuff better 2024-04-05 21:20:34 +13:00
Luke D. Jones
4701c019a8 Major cleanup of older gui state code 2024-04-05 20:19:07 +13:00
Luke D. Jones
ca0d8bda4b Update readme. Fix tray startup 2024-04-05 16:00:20 +13:00
Luke D. Jones
a271ffbb10 rcc: run as app only on Ally 2024-04-04 09:58:40 +13:00
Luke D. Jones
00babaf949 Update translations 2024-04-03 16:15:09 +13:00
Luke D. Jones
2f844ac151 Cleanup 2024-04-03 16:15:09 +13:00
Luke D. Jones
5178bf1d1a Update readme 2024-04-03 16:15:09 +13:00
jochen@g14
116afb9b6c Initialize slash from config file 2024-03-31 01:08:26 +01:00
jochen@g14
4468a58487 Use enable/disable commands and cleanup build warnings 2024-03-31 00:34:44 +01:00
jochen@g14
2f73577e91 Fix Cargo.toml 2024-03-30 23:33:30 +01:00
jochen@g14
c1cffc8f59 Remove example file since it's not correct 2024-03-30 23:29:55 +01:00
jochen@g14
6d8f85c154 Minor changes to reflect original files 2024-03-30 23:27:33 +01:00
jochen@g14
0674e7f61c Changes after my own PR review 2024-03-30 23:23:37 +01:00
jochen@g14
fde2f3ba15 Fixed issues with asusctl-slash command 2024-03-30 21:19:55 +01:00
jochen@g14
70493d1a93 Fix error in makefile 2024-03-30 19:39:42 +01:00
jochen@g14
c20d0a76a0 Fix build after merge 2024-03-30 19:00:22 +01:00
jochen@g14
e6952e241a Merge from main 2024-03-30 18:44:15 +01:00
jochen@g14
b40812928a Imlement Display and FromStr traits for SlashMode 2024-03-30 18:42:42 +01:00
jochen@g14
8cdc9773c9 Added working implementation of the G14 Slash ledstrip 2024-03-30 18:41:31 +01:00
Luke Jones
8d30282edf Update default.md 2024-03-28 01:03:30 +00:00
Luke D. Jones
4ba44560a9 Update deps 2024-03-27 19:27:22 +13:00
jochen@g14
cdc9ca7b58 Try to implement slash bar functionality - part 1 2024-03-25 01:54:05 +01:00
Luke D. Jones
7eae7c5664 Change aura manager task to blocking. Remove idle tasks that keep hanging 2024-03-24 21:14:54 +13:00
Luke D. Jones
739a0ffa63 aura debugging 2024-03-24 10:55:20 +13:00
Luke D. Jones
637360095c Shift init actions up a few calls to prevent over-eager init 2024-03-23 23:27:26 +13:00
Luke D. Jones
4b34ab83fb Initial pass of async task sync in aura 2024-03-23 23:15:38 +13:00
Luke D. Jones
ac605cbc00 Narrow the search space of aura devices down 2024-03-23 14:30:00 +13:00
Luke D. Jones
4b38e5daa6 Further adjustments to aura 2024-03-23 13:07:20 +13:00
Luke D. Jones
1c007b4216 Small refinement to aura control init 2024-03-23 11:45:20 +13:00
Luke D. Jones
193f9dfa1e Extra logging for aura 2024-03-23 11:27:20 +13:00
Jochen@Jinbe
1366422d96 Play around and add rog-slash 2024-03-22 22:05:27 +01:00
Luke D. Jones
4e778a3d28 Refactor HidRaw 2024-03-22 19:47:24 +13:00
Luke D. Jones
be05508110 Try to ensure all aura are detected at start 2024-03-22 17:36:58 +13:00
Luke D. Jones
9119229d41 Update deps 2024-03-20 23:12:52 +13:00
Luke D. Jones
5c43c31331 Manage add/remove aura
Serialize aura config filename
2024-03-20 23:00:25 +13:00
Luke D. Jones
014604724f Fix clippy lints 2024-03-15 19:41:38 +13:00
Luke D. Jones
7d076368e9 Adjust organization of rog control src 2024-03-15 17:19:54 +13:00
Luke D. Jones
5d6ed5c365 Remove old screenshits 2024-03-14 22:17:42 +13:00
Luke D. Jones
a2b8f0f93c Minor updates 2024-03-14 22:10:14 +13:00
Luke D. Jones
5fe8416c65 Only apply fan curve for profile if *on* that profile, but still save config 2024-03-14 21:28:06 +13:00
Luke D. Jones
1b4d7a95af Minor corrections 2024-03-14 21:24:28 +13:00
Luke D. Jones
e8627fde4c Fix applying disabled and enabled fan curves 2024-03-14 21:11:18 +13:00
Luke D. Jones
6b0edc6da1 Enable fan curves 2024-03-14 17:17:55 +13:00
Luke D. Jones
f6ad631a0f Update readme 2024-03-14 11:19:31 +13:00
Luke D. Jones
f6393a3926 Further fan-curve graph work 2024-03-13 23:30:06 +13:00
Luke D. Jones
d51384c3a1 Fix the fan curve defaults again 2024-03-13 21:19:01 +13:00
Luke D. Jones
78f18959fb Populate fan curve data 2024-03-13 20:18:41 +13:00
Luke D. Jones
7a661a585e Add missing file 2024-03-13 19:14:29 +13:00
Luke D. Jones
f4f7a1e648 Check in the fan curve work 2024-03-13 18:57:38 +13:00
Luke D. Jones
b6e3e5e823 Remove a dbg 2024-03-13 14:08:43 +13:00
Luke D. Jones
41b1bd23d6 Fix fancurves 2024-03-13 14:08:08 +13:00
Luke D. Jones
69458a0595 Minor fix to graph widget 2024-03-12 22:06:56 +13:00
Luke D. Jones
5fd107df27 Initial fan graph widget 2024-03-12 21:33:39 +13:00
Luke D. Jones
2558057e9f Use mix instead of interpolate 2024-03-12 00:09:54 +13:00
Luke D. Jones
8111daaf1d Use mix instead of interpolate 2024-03-12 00:08:54 +13:00
Luke D. Jones
672acb234f Make aura settings apply instantly 2024-03-11 23:27:07 +13:00
Luke D. Jones
9725062fb9 Refactor and cleanup theming 2024-03-11 22:26:26 +13:00
Luke D. Jones
c7b1624313 Remove dbg statements 2024-03-11 12:53:38 +13:00
Luke D. Jones
67b97f1d43 Update ci and readme 2024-03-10 23:29:50 +13:00
Luke D. Jones
6498fd1349 Move rog<->slint type conversions to module 2024-03-10 21:12:36 +13:00
Luke D. Jones
e371229b6c Update support for boot_sound kernel patch 2024-03-10 20:53:03 +13:00
Luke D. Jones
0fac33a8ff Update pipeline 2024-03-09 23:49:42 +13:00
Luke D. Jones
b0da062577 Clean up debug info 2024-03-09 23:30:15 +13:00
Luke D. Jones
ca41bd59de Begin implmenting keyboard power states 2024-03-09 23:18:30 +13:00
Luke D. Jones
efcad3f6f9 Small colour correction 2024-03-06 22:41:55 +13:00
Luke D. Jones
fa2255cbaf Atempt better aura colour mix 2024-03-06 22:35:16 +13:00
Luke D. Jones
02b9bac899 Clean up the tray code 2024-03-04 13:28:19 +13:00
Luke D. Jones
a1fcf5023c Force tray process to exit if Quit 2024-03-03 22:41:57 +13:00
Luke D. Jones
2f8ea80e6d Replace shitty gtk tray with betrayer 2024-03-03 22:26:52 +13:00
Luke D. Jones
b798cf6a4e Minor adjust to rgb bright slider 2024-03-03 13:30:46 +13:00
Luke D. Jones
3da848d131 Init with colour sliders in approx position 2024-03-03 12:57:45 +13:00
Luke D. Jones
a88c33c201 MOrE 2024-03-02 23:49:11 +13:00
Luke D. Jones
7b0f037cba Trying different strategies for non-blocking UI 2024-02-25 23:21:11 +13:00
Luke D. Jones
91b1456d06 Formulate slint patterns 2024-02-25 19:24:20 +13:00
Luke D. Jones
c3b02a2bb0 Fix the IPC 2024-02-25 13:09:13 +13:00
Luke D. Jones
8e4b7d53f4 More updating to zbus 4.0.1 2024-02-24 21:56:52 +13:00
Luke D. Jones
a44145f487 Update to zbus 4.0.1 2024-02-24 21:56:29 +13:00
Luke D. Jones
bb7b3a81fb Bump version 2024-02-24 21:50:52 +13:00
Luke D. Jones
19607d71c3 Prep 5.0.8 release 2024-02-24 17:09:24 +13:00
Luke D. Jones
96f281d789 Remove the use of bytes in zbus signatures 2024-02-23 21:50:53 +13:00
Luke D. Jones
7613eded95 Sane defaults for asusd config 2024-02-23 14:40:00 +13:00
Luke D. Jones
50eccd2b1d Formatting and fixes 2024-02-23 12:36:16 +13:00
Luke Jones
ba54007102 Merge branch 'bugfix/persistent-theme' into 'main'
Reintroduce persistent dark/light mode

See merge request asus-linux/asusctl!180
2024-02-19 19:44:59 +00:00
Filip Binkiewicz
a028f5375f Reintroduce persistent dark/light mode 2024-02-19 19:27:56 +00:00
Luke Jones
9ec02cd727 Merge branch 'dearner-main-patch-22870' into 'main'
Added G814JZ to aura_support.ron (uses G814JI keymap)

See merge request asus-linux/asusctl!179
2024-02-14 01:40:26 +00:00
Chris Dearner
4b46ece09a Added G814JZ to aura_support.ron (uses G814JI keymap) 2024-02-05 12:49:49 +00:00
Luke D. Jones
086bbd0908 Fix the broken pipe error 2024-02-02 23:26:41 +13:00
Luke D. Jones
c94eaa473e Update TS bindings 2024-01-24 22:37:10 +13:00
Luke D. Jones
b1b809834b Reload and apply settings if config file externally changed 2024-01-24 12:19:34 +13:00
Luke D. Jones
84183288ec Fix inotify watch failing thanks to vim idiocy 2024-01-23 22:44:20 +13:00
Luke D. Jones
86cbef83b6 Reload asusd.ron if changed 2024-01-22 21:54:19 +13:00
Luke D. Jones
006fb632c4 Doc and feature fixes 2024-01-22 19:33:40 +13:00
Luke D. Jones
e3636ed8ce Update smithay-client-toolkit 2024-01-22 12:06:42 +13:00
Luke D. Jones
cfd207f251 Remove async-trait crate and set min rustc 1.75 2024-01-15 18:22:41 +13:00
Luke D. Jones
d4c68546e7 Added ability to change what EPP is linked with each throttle profile 2024-01-15 18:00:27 +13:00
Luke D. Jones
6f4a7e16dc Fixes to RCC 2024-01-05 14:21:31 +13:00
Luke D. Jones
f64253d633 Various bugfixes 2024-01-05 13:53:57 +13:00
Luke D. Jones
124c17aadc Add default issue template 2024-01-04 14:30:11 +13:00
Luke D. Jones
ab40f9fcbf Add FX705D led support 2024-01-04 09:23:37 +13:00
Luke D. Jones
5cdfa5a8d4 Fix to suspend process in anime thread to let custom anims run on wake 2023-12-27 11:24:39 +13:00
Luke D. Jones
ce870cd5ed Revert egui update due to a lot of issues arising from window closing 2023-12-27 10:13:26 +13:00
Luke D. Jones
4541d2e1ba Update dbus introspection 2023-12-26 11:56:47 +13:00
Luke D. Jones
b525411fd3 Minor fixes in asusctl 2023-12-25 21:24:05 +13:00
Luke D. Jones
a867496f13 Re-enable ROGCC fan curves 2023-12-24 10:30:33 +13:00
Luke D. Jones
f421b8ee3b Fix to apply led effect in rogcc 2023-12-23 21:45:19 +13:00
Luke D. Jones
82780feb4b Update readme 2023-12-23 10:37:46 +13:00
Luke D. Jones
1e5443e206 Bugfix release 2023-12-22 11:39:17 +13:00
Luke D. Jones
027a591d26 Add cargo-vendor-filterer to pipeline 2023-12-17 21:44:33 +13:00
Luke D. Jones
e90375828d Fix: nuke some async deadlocks in fan-curves 2023-12-17 21:41:07 +13:00
Luke D. Jones
75b4d67072 Fix: force Anime power/wakeup disabled to prevent idiotic random wakes 2023-12-15 19:15:14 +13:00
Luke D. Jones
9aa332de3b New release 2023-12-15 11:50:49 +13:00
Luke D. Jones
5efd7fc6a7 Fix: Corrections to dbus signature for some keyboard power settings
Closes #423
2023-12-15 11:48:20 +13:00
Luke D. Jones
0aafe24a02 Fix: correctiosn to asusd.service
Closes #424
2023-12-15 11:48:20 +13:00
Luke D. Jones
dda6d343d9 Fix: correction to switching next fan profile
Closes #425
2023-12-15 11:48:18 +13:00
Luke D. Jones
6f39307080 remember how to tag releases 2023-12-12 22:00:37 +13:00
Luke Jones
ef63789faa Merge branch 'main' into 'main'
Added missing button, and fixed layout for Strix G18

See merge request asus-linux/asusctl!176
2023-12-12 08:58:31 +00:00
Sunehildeep Singh
c422e77ba6 Added missing button, and fixed layout for Strix G18 2023-12-12 08:58:31 +00:00
Luke D. Jones
3c234dd3c4 Release 5.0.0 2023-12-12 21:54:24 +13:00
Luke Jones
c420dd820a Merge branch '419-support-for-strix-g18-aura-g814ji-already-done-need-merge' into 'main'
Draft: Resolve "Support For Strix G18 AURA (G814JI) - Already Done, need merge"

Closes #419

See merge request asus-linux/asusctl!175
2023-12-10 20:03:55 +00:00
Luke D. Jones
a3e6fec163 Add g814ji and layout 2023-12-11 08:56:17 +13:00
Luke D. Jones
9b4e76be87 Update examples 2023-12-11 08:49:32 +13:00
Luke D. Jones
7b2125cbdf fic async deadlock in platform control 2023-12-08 20:06:22 +13:00
Luke D. Jones
694a644cc6 Revert "Fix: change epp change watch to a loop to prevent deadlock"
This reverts commit c06f78990f.
2023-12-08 20:06:22 +13:00
Luke D. Jones
922aa0c352 platform example testing 2023-12-08 17:33:27 +13:00
Luke D. Jones
c06f78990f Fix: change epp change watch to a loop to prevent deadlock 2023-12-07 20:04:21 +13:00
Luke D. Jones
5c8bb6e6ea Ensure thermal policy is set on resume and relaod 2023-12-05 19:26:49 +13:00
Luke Jones
993131d0a9 Merge branch 'fluke/dbus-refactor' into 'main'
Fluke/dbus refactor

See merge request asus-linux/asusctl!173
2023-12-03 20:44:01 +00:00
Luke Jones
0a69c23288 Fluke/dbus refactor 2023-12-03 20:44:01 +00:00
Luke D. Jones
f6e4cc0626 Cleanup after changes from Platform dbus rework 2023-11-18 22:36:55 +13:00
Luke D. Jones
1f696508e7 rog-platform: refactor all related parts 2023-11-18 21:57:46 +13:00
Luke D. Jones
fa043adc99 rog-platform: add CPU and GPU tunings
rog-platform: add tunables to supported dat

Anime: fixes to how some power options work
2023-11-17 17:16:03 +13:00
Luke D. Jones
b9c2d929b3 anime: rework sleep logic 2023-11-16 13:57:42 +13:00
Luke D. Jones
eda1e920df Update changelog 2023-11-15 18:29:35 +13:00
Luke D. Jones
0de2c9e424 Anime: remove sleep animation config 2023-11-15 18:27:58 +13:00
Luke D. Jones
e88e7be8ae Anime: expose new options in CLI 2023-11-15 17:45:52 +13:00
Luke D. Jones
e470d3acc0 Anime: add dbus methods 2023-11-15 17:23:44 +13:00
Luke D. Jones
f5b3f0bc38 Fix lints on examples 2023-11-15 17:23:35 +13:00
Luke D. Jones
19497c94e0 Anime: fix data struct 2023-11-15 16:56:50 +13:00
Luke D. Jones
670eee23e8 Anime: small cleanup 2023-11-15 16:45:30 +13:00
Luke D. Jones
26309776e9 Fix test 2023-11-15 14:47:52 +13:00
Luke D. Jones
a7d5057976 Anime: propagate property config 2023-11-15 14:46:42 +13:00
Luke D. Jones
8eb9b1d4eb Anime: refactor power stuff 2023-11-15 14:29:38 +13:00
Luke D. Jones
71ee9e43ba Fix gnome-45 extension version 2023-11-14 16:49:17 +13:00
Luke D. Jones
f1b0e1288a Add missing crates 2023-11-13 11:28:34 +13:00
Luke D. Jones
35c7fd10b3 Drop sysfs_class and create dmi_id for getting identifying info with udev 2023-11-08 14:00:35 +13:00
Luke D. Jones
4c50dc259c rog-control-center: ensure brightness slider works correctly 2023-11-08 13:59:07 +13:00
Luke D. Jones
0fd0aeff88 Support Rog Ally LED modes (basic) 2023-11-07 17:24:38 +13:00
Luke Jones
fd37f41ef1 Merge branch 'sctk-0.16.1' into 'main'
cargo update -p smithay-client-toolkit v0.16.0 -> v0.16.1

Closes #407

See merge request asus-linux/asusctl!172
2023-10-11 06:30:37 +00:00
Cole Mickens
1307997122 cargo update -p smithay-client-toolkit v0.16.0 -> v0.16.1 2023-10-11 08:15:04 +02:00
Luke Jones
85187d2d8d Merge branch 'add_laptop_G513RW' into 'main'
Added preliminary support for G513RW

See merge request asus-linux/asusctl!171
2023-09-16 05:51:15 +00:00
Edwin Clement
e29a568195 Added preliminary support for G513RW 2023-09-15 20:03:02 -04:00
Luke D. Jones
6c375a9951 Prep new release 2023-09-08 13:22:15 +12:00
Luke D. Jones
4641e19c43 Fix bad keybaord layout 2023-09-04 10:19:57 +12:00
Luke D. Jones
91f0c2ea14 Fix loading of fan curves
Closes #402

Signed-off-by: Luke D. Jones <luke@ljones.dev>
2023-09-04 10:18:48 +12:00
Luke Jones
b4a8cb9de2 Merge branch 'srivatsarog-main-patch-78688' into 'main'
Update aura_support.ron

See merge request asus-linux/asusctl!169
2023-09-03 08:45:39 +00:00
Luke Jones
67bbcdb964 Merge branch 'main' into 'srivatsarog-main-patch-78688'
# Conflicts:
#   rog-aura/data/aura_support.ron
2023-09-03 08:37:52 +00:00
Luke Jones
8acfe0a9e8 Merge branch 'main' into 'main'
aura: Support for G733PZ

See merge request asus-linux/asusctl!167
2023-09-03 08:36:20 +00:00
Luke D. Jones
5f6e6ec382 gex: rename gnome-44, add gnome-45 2023-08-31 14:36:01 +12:00
Luke D. Jones
cf92526d87 Set cargo resolver 2023-08-31 12:42:31 +12:00
Luke D. Jones
f290594562 Prep release 2023-08-26 21:40:45 +12:00
Luke D. Jones
423bd54f79 Fixes: bugfixes in aura config loading 2023-08-26 21:35:38 +12:00
Luke Jones
ea0eaef8a6 Update README.md 2023-08-24 10:22:26 +00:00
Luke Jones
ef62a26148 Merge branch 'main' into 'main'
add aura support for GU603VV

See merge request asus-linux/asusctl!170
2023-08-20 06:13:20 +00:00
Yifan Zhu
2f916fa4e5 add aura support for GU603VV 2023-08-20 06:13:20 +00:00
Luke D. Jones
e42fd10404 Update deps 2023-08-14 13:20:40 +12:00
Luke D. Jones
93edd1b632 Add gv601v singlezone advanced 2023-08-13 18:22:21 +12:00
Luke D. Jones
6957a08d83 Fix: Corrections in anime detection
Closes #387
2023-08-11 09:48:22 +12:00
Luke D. Jones
98569b98e7 Remove a dbg!() x2 2023-08-10 09:50:01 +12:00
Luke D. Jones
573568d6e2 Remove a dbg!() 2023-08-10 09:49:13 +12:00
Luke D. Jones
3ec37a4dac Fix: For anime look for usbraw device before hidraw device
Closes #387
2023-08-02 14:14:08 +12:00
Luke D. Jones
11483b28a6 Fix: Further refine the CLI for fan curve control
Should close #385
2023-08-01 19:30:33 +12:00
Luke D. Jones
2cce83d164 Fix: asusd should reload defualt fan-curves if the config file fails
Closes #385
2023-08-01 09:30:54 +12:00
Luke D. Jones
42b92f3b87 Fix: reimplement fetching of fan curves on CLI
Partial close of #385
2023-08-01 09:18:27 +12:00
gabi
b652fd15a2 Update aura_support.ron 2023-07-28 06:16:39 +00:00
Luke D. Jones
9154aaa97c Add distro packaging dir + spec file for fedora 2023-07-27 10:13:10 +12:00
Interfector18
9e65921c0a aura: Support for G733PZ 2023-07-24 17:44:59 +02:00
Luke D. Jones
8d8b5e5f51 aura: support GV601V LED modes 2023-07-24 14:07:01 +12:00
Luke D. Jones
9418b63454 Bump new release 2023-07-24 10:23:05 +12:00
Luke D. Jones
2d396a49da Update crate versions 2023-07-24 10:14:24 +12:00
Luke D. Jones
a6d89a622b Various cleanup. Add GA402X LED modes 2023-07-24 10:04:10 +12:00
Luke D. Jones
51bcb0082b profiles: add mid fan curve support 2023-07-24 09:29:56 +12:00
Luke D. Jones
eb54250e4d aura: support FX505G 2023-07-24 09:28:09 +12:00
Luke D. Jones
eafc831231 gex: update xml and aura power parsing 2023-07-12 14:21:57 +12:00
Luke D. Jones
c625e97b7b Update changelog 2023-07-11 21:08:10 +12:00
Luke D. Jones
fea56879d6 Update changelog 2023-07-11 21:06:27 +12:00
Luke D. Jones
03052e129b aura: update dbus xml 2023-07-11 21:02:40 +12:00
Luke D. Jones
3dbc893905 aura: update bindings 2023-07-11 21:00:42 +12:00
Luke D. Jones
50152961c7 aura: refactor modern rog power settings 2023-07-11 20:59:43 +12:00
Luke D. Jones
8be0e7e6bf gex: update laptop feature toggle to switch primary 2023-07-06 22:00:59 +12:00
Luke D. Jones
d6d4a00fc3 gex: add keyboard LED mode setting 2023-07-04 21:22:30 +12:00
Luke D. Jones
611140716c gex: map more of dbus methods and notifs 2023-07-04 20:08:42 +12:00
Luke D. Jones
a09f7b5275 gex: parse led power from dbus 2023-07-04 18:49:52 +12:00
Luke D. Jones
823958492e rename keyboard led power dbus methods 2023-07-04 10:17:11 +12:00
Luke D. Jones
668135eab3 Update readme 2023-07-03 23:06:19 +12:00
Luke D. Jones
622e07505d gex: begin adding aura control dbus 2023-07-03 23:04:06 +12:00
Luke D. Jones
5c159d2294 Set toolchain to stable 2023-07-03 20:14:14 +12:00
Luke D. Jones
6cfa09a02b Update readme 2023-07-03 16:20:46 +12:00
Luke D. Jones
95666cc40b Update deps 2023-07-03 16:07:38 +12:00
Luke D. Jones
458d58c87c Update changelog 2023-07-03 16:05:46 +12:00
Luke D. Jones
7328ebdda3 gex: cleanup and rename 2023-07-03 15:51:26 +12:00
Luke D. Jones
14d043bbc3 RCC: add tray enable/disable, move app settings to page 2023-07-03 15:02:25 +12:00
Luke D. Jones
98dec6403c gex: adjust tsconfig 2023-07-02 21:58:50 +12:00
Luke D. Jones
3546f5bd21 gex: add toggle for anime powersave anim 2023-07-02 21:09:17 +12:00
Luke D. Jones
db1683de46 gex: temporary checking of which primary quicktoggle to use 2023-07-02 19:15:55 +12:00
Luke D. Jones
669c8ac3c7 gex: make quickmenu a module 2023-07-02 17:30:20 +12:00
Luke D. Jones
4f3a6ce1c6 gex: trial of using qucik submenu toggles 2023-07-02 11:37:36 +12:00
Luke Jones
6d3918ccf0 clean up bindings 2023-07-01 12:00:46 +00:00
Luke D. Jones
b002187b39 gex: trial of updating quicktoggle with dbus signal 2023-07-01 23:14:54 +12:00
Luke D. Jones
13965b2261 gex: add eslint, cleanup parsing of some stuff 2023-07-01 21:47:31 +12:00
Luke D. Jones
b182fbd323 gex: add anime power quicktoggle 2023-07-01 20:09:28 +12:00
Luke D. Jones
19b28f202c gex: Add slider for charge control 2023-07-01 19:17:02 +12:00
Luke D. Jones
ed51a7fa14 gex: fix and update 2023-07-01 18:03:05 +12:00
Luke D. Jones
c94358a8f3 gex: itemize the quicks and indicators 2023-07-01 17:18:11 +12:00
Luke D. Jones
2a8ca0a39a asusd: cleanup platform notifs, prevent more duplications 2023-07-01 12:31:40 +12:00
Luke D. Jones
83455a5ba3 Update deps 2023-06-30 15:57:18 +12:00
Luke D. Jones
bc776deb70 gex: more cleanup 2023-06-30 11:30:09 +12:00
Luke D. Jones
59b1059aee gex: cleanup 2023-06-30 10:43:19 +12:00
Luke D. Jones
dbe80d1914 gex: simplify build 2023-06-29 23:05:00 +12:00
Luke D. Jones
e325ebed18 gex: working quicktoggle example 2023-06-29 20:48:15 +12:00
Luke D. Jones
a743bda6e0 gex: cleanup 2023-06-29 17:42:57 +12:00
Luke D. Jones
15e6782e10 gex: map anime dbus data 2023-06-29 15:16:21 +12:00
Luke D. Jones
6b058c9922 gex: trial of dbus mthods 2023-06-29 12:58:11 +12:00
Luke D. Jones
fc8879ac24 gex: dbus class template 2023-06-28 22:50:56 +12:00
Luke D. Jones
4d2d5707a1 Begin reimplement gex to use generated bindings and dbus xml 2023-06-28 21:54:17 +12:00
Luke D. Jones
439c830311 Cleanup rog-aura usb tests 2023-06-28 10:07:11 +12:00
Luke D. Jones
91223d4ced Regenerate dbus xml 2023-06-27 22:19:29 +12:00
Luke D. Jones
7b17a13ce7 ridiculous refactor to allow enums to be dbus strings for better TS generation 2023-06-27 21:16:13 +12:00
Luke D. Jones
fca7d23a31 Update pipeline 2023-06-26 13:54:07 +12:00
Luke D. Jones
0122138b3b Add index.html 2023-06-26 13:43:06 +12:00
Luke D. Jones
7b495e7587 rcc: instant apply keyboard settings 2023-06-26 12:28:48 +12:00
Luke D. Jones
970cf9ae59 Support for G634J LED modes (layout is in progress) 2023-06-26 12:01:21 +12:00
Luke D. Jones
ad990c6ae1 Move G513I* to G513I in arua DB to catch full series of this range
Closes #336
2023-06-26 11:52:14 +12:00
Luke D. Jones
cd8cc013a4 Aura: set the LED brightness if settign a mode
Closes #355
2023-06-26 11:33:05 +12:00
Luke D. Jones
acf41c1783 Add support for mini_led_mode get/set
- asusd get/set, zbus methods
- Rog control center notification, tray menu, UI entry
2023-06-26 10:44:58 +12:00
Luke D. Jones
03c9f06569 asusctl: remove the panics from CLI
closes #364
2023-06-26 09:41:42 +12:00
Luke D. Jones
036a5018e0 Removed a duplication of charge limit notification 2023-06-25 21:15:27 +12:00
Luke D. Jones
81529b7374 Update GL503 led config 2023-06-25 20:59:26 +12:00
Luke D. Jones
2289af3ef6 Update discord link.
Closes #363
2023-06-25 20:51:17 +12:00
Luke D. Jones
633ffdf962 Support for GV601VI LED modes
Closes #370
2023-06-25 20:49:28 +12:00
Luke D. Jones
cb88c9f0e2 Fix: prevent multiple notifications from profile change 2023-06-25 20:43:43 +12:00
Luke D. Jones
8b77078a6f Animatrix: simulators, add features 2023-06-25 18:29:19 +12:00
Luke D. Jones
3d6d92ae7d Animatrix: gu604 sim 2023-06-25 16:36:19 +12:00
Luke D. Jones
55723b7b77 animatrix mapping: gu604 2023-06-25 11:39:56 +12:00
Luke D. Jones
7796ba0603 Animatrix sim: fixxess 2023-06-24 22:02:21 +12:00
Luke D. Jones
d3aababef5 animatrix simulator for ga402 2023-06-24 19:00:25 +12:00
Luke D. Jones
4611c08085 Add the missing dirs, dumbarse 2023-06-24 13:15:11 +12:00
Luke D. Jones
0a008a653a Animatrix: Default to GA402 style if Unknown, use default-workspace.
Also rename daemon crates to the bin names they use to be less confusing.

Signed-off-by: Luke D. Jones <luke@ljones.dev>
2023-06-24 12:57:03 +12:00
Luke D. Jones
cd5daa17d0 Anime: Enabled setting builtin animations 2023-06-21 13:34:08 +12:00
Luke D. Jones
a0529e0efd Better organise anime tests 2023-06-21 10:09:06 +12:00
Luke D. Jones
3e0aeea6c6 Add inotify::WatchMask::MODIFY to inotify watch mask.
Closes #362
2023-06-20 22:23:54 +12:00
Luke D. Jones
e2fb1d44b5 Anime: Diagonal asus gifs done 2023-06-20 21:58:27 +12:00
Luke D. Jones
04543eeca0 Aura: add support for Rear Glow power modes 2023-06-18 19:48:08 +12:00
Luke D. Jones
68ee62fef1 Anime: add base brightness control (dbus, cli) 2023-06-16 11:50:38 +12:00
Luke D. Jones
e523e4e9a2 Anime: GU604 images correct 2023-06-16 10:43:15 +12:00
Luke D. Jones
ea2d80cc44 Anime: incorrect dimensions and pitch 2023-06-16 00:34:45 +12:00
Luke D. Jones
40e00c4739 Anime: fixups, GU604 support 2023-06-15 23:53:24 +12:00
Luke D. Jones
cdc42193d1 Update deps 2023-06-14 20:30:42 +12:00
Luke D. Jones
3a18506510 Add "Unknown" to (not really) supported AniMe list
Intention is to allow users to at least control the power state of the
device (turn off) if the phyciscal display isn't yet supported.

Partial address of #354
2023-06-14 20:25:27 +12:00
Luke D. Jones
fa671e53d8 Add sdl32 to gitlab pipeline 2023-06-14 20:25:27 +12:00
Luke D. Jones
002dc8516d Half-arsed visuals for virtual anime 2023-06-14 20:25:27 +12:00
Luke D. Jones
2a38f69cc4 Begin implementing virtual devices for testing and stuff 2023-06-14 20:25:27 +12:00
Luke Jones
a14a37d0da Merge branch 'optional-stripping' into 'main'
Optional symbol stripping in Makefile

See merge request asus-linux/asusctl!165
2023-06-13 23:17:22 +00:00
Greg Land
b105ff5180 Optional symbol stripping in Makefile
Packaging systems have options to handle symbol stripping.  This lets
the users of the software enable or disable symbol stripping based on
their own preference or need.
2023-06-13 19:01:08 -04:00
Luke Jones
d202fcd97a Merge branch 'fix-install-program-target' into 'main'
Fixed issue preventing debug builds using Makefile

See merge request asus-linux/asusctl!163
2023-06-13 21:41:56 +00:00
Greg Land
15732ecd82 Fixed issue preventing debug builds using Makefile
install-program was always assuming that release was the only target
directory that could exist.  This would cause install-program to fail
with DEBUG=1 passed to the makefile.

DEBUG flag now correctly sets a TARGET and sets the build profile to dev
for debug builds.
2023-06-13 13:30:23 -04:00
Luke Jones
8508110ba0 Merge branch 'fix-g513qy' into 'main'
Fix broken Aura on G513QY

See merge request asus-linux/asusctl!162
2023-06-07 07:09:00 +00:00
CryoByte33
cafb64d57b Fix broken Aura on G513QY 2023-06-07 04:36:38 +02:00
Luke D. Jones
7515eafc45 Rmeove notification handle tracking limit
Fixes issue with KDE profile change notif disappearing.

closes #353
2023-05-20 19:07:40 +12:00
Luke D. Jones
b6c6f10bdf Fix test 2023-05-20 19:05:22 +12:00
Luke D. Jones
35352a8a7c Support for GL503V LED modes 2023-05-20 19:04:18 +12:00
Luke Jones
0c3bebdeb9 Merge branch 'main' into 'main'
Add led modes for GV601VI

See merge request asus-linux/asusctl!161
2023-05-16 22:57:50 +00:00
Mateo Juric
1394c12967 Add led modes for GV601VI 2023-05-17 00:04:36 +02:00
Luke D. Jones
cbc1f6f5bb Modify two TUF aura DB entries to match full range 2023-04-27 19:46:17 +12:00
Luke D. Jones
7ae0f896cf Update deps 2023-04-27 16:08:52 +12:00
Luke D. Jones
fb0374512d Fix rog-control-center not reopening if is set 2023-04-27 16:01:07 +12:00
Luke D. Jones
14f031ad34 Better update of aura modes if supported list changed 2023-04-27 10:57:45 +12:00
Luke D. Jones
bee5508099 Prep new release 2023-04-26 22:00:22 +12:00
Luke D. Jones
c741204200 Prep new release 2023-04-26 21:59:13 +12:00
Luke D. Jones
858c9841a7 Update deps 2023-04-26 21:35:48 +12:00
Luke D. Jones
fdc7d88a70 More tweaks to notifications 2023-04-26 12:49:29 +12:00
Luke D. Jones
da3017bb89 Update supergfx dep 2023-04-26 12:32:26 +12:00
Luke D. Jones
641e762e80 Update deps 2023-04-26 11:24:50 +12:00
Luke D. Jones
25ecfda095 Various tray and notification improvements 2023-04-26 10:57:13 +12:00
Luke D. Jones
31af8f9511 Use egui without wayland feature due to segfault 2023-04-25 14:44:31 +12:00
Luke D. Jones
8db783d9b4 Better handling of supergfx version check, aura config updates 2023-04-25 13:57:07 +12:00
Luke D. Jones
45a354880a Add support for GV604 LEDs 2023-04-25 12:13:20 +12:00
Luke D. Jones
ca1c67e803 Begin fixing up support of basic modes + supergfx 2023-04-25 10:27:09 +12:00
Luke D. Jones
c819fa458a Optimise keyboard detection 2023-04-24 22:23:42 +12:00
Luke D. Jones
869ab90299 Add 0x18c6 keyboard 2023-04-24 20:54:51 +12:00
Luke D. Jones
c40029f5e7 Merge branch 'fluke/18c6-keyboard' 2023-04-24 20:15:11 +12:00
Luke Jones
e864dfb0e7 Merge branch 'feature/persistent-theme' into 'main'
Persistent dark / light mode

See merge request asus-linux/asusctl!160
2023-04-22 21:29:36 +00:00
Filip
476b394add Persistent dark / light mode 2023-04-22 21:29:36 +00:00
Luke D. Jones
4ea5480e66 Add support for GX650P LED modes 2023-04-21 11:01:54 +12:00
Luke Jones
cfc46a2b70 Merge branch 'guv604vi-support' into 'main'
Add led modes for GU604VI

See merge request asus-linux/asusctl!159
2023-04-20 22:32:50 +00:00
bno1
235763a615 Add led modes for GU604V 2023-04-21 00:36:00 +03:00
Luke D. Jones
6e19c16e70 Begin adding 18c6 keyboard support
This keyboard is found in ROG Flow Z13 machines. A kernel patch is also
required for full support.

Addresses #344.
2023-04-19 12:08:30 +12:00
Luke D. Jones
6ea550b6ff Update egui and supergfxctl deps
Requires running with supergfxctl v5.1.0-RC5 if installed
2023-04-19 10:12:14 +12:00
Luke Jones
dd30c8092b Merge branch 'pr-makefile-split' into 'main'
Makefile: split install into install-{program,data}

See merge request asus-linux/asusctl!158
2023-04-10 08:04:40 +00:00
Cole Mickens
2bd751f841 Makefile: split install into install-{program,data} 2023-04-09 18:44:55 -05:00
Luke Jones
7a6aafded7 Merge branch 'fluke/fix-anime-loops' into 'main'
Bugfix: Adjust how sub-llops and part of anime animation handle

See merge request asus-linux/asusctl!157
2023-04-08 03:40:32 +00:00
Luke Jones
940b93a75f Merge branch 'zpl/fix-anime-loops_fix' into 'fluke/fix-anime-loops'
fix: sleep-animation

See merge request asus-linux/asusctl!156
2023-04-04 21:36:48 +00:00
Armas Spann
5c70fec29a fix: sleep-animation 2023-04-04 01:20:25 +02:00
Luke Jones
8ac505e0dd Merge branch 'main' into 'main'
Add support for FX506LH keyboard layout

See merge request asus-linux/asusctl!155
2023-04-03 08:13:07 +00:00
Luke D. Jones
3bdb03b1d8 Bugfix: Adjust how sub-llops and part of anime animation handle
Attempts to address #332
2023-04-03 20:01:06 +12:00
Winfried
4ac4909881 Add support for FX506LH keyboard layout 2023-03-29 15:12:03 +03:00
Luke D. Jones
ec5e6d2e7c Add support for G533Z keyboard and modes
Closes #327
2023-03-20 08:52:23 +01:00
Luke D. Jones
5600c51ba0 Fix remove the leftover initial config writes on new() for some controllers
Closes #320
2023-01-25 09:27:12 +13:00
Luke D. Jones
cb5856c4dc Update fedora build instruction 2023-01-18 20:40:25 +13:00
Luke Jones
aad6f6350b Update README.md 2023-01-17 20:54:46 +00:00
Luke D. Jones
1ec45a6449 Update gitlab CI 2023-01-16 15:17:37 +13:00
Luke Jones
bb612283fe Update .gitlab-ci.yml file 2023-01-16 02:00:34 +00:00
Luke Jones
bcba11d4ec Update .gitlab-ci.yml file 2023-01-16 01:59:50 +00:00
Luke Jones
7eab94bc7f Update .gitlab-ci.yml file 2023-01-16 01:57:55 +00:00
Luke D. Jones
e73bbedb41 Properly enable pipeline cache? 2023-01-16 14:50:50 +13:00
Luke D. Jones
a83ccbd33d Add git hooks via cargo-husky. Many many cleanups. 2023-01-16 13:23:30 +13:00
Luke Jones
b5b7799018 Merge branch 'readme-popos-instructions-typo-fix' into 'main'
Fixed typo in the instructions for Pop_OS installation commands

See merge request asus-linux/asusctl!152
2023-01-15 21:04:36 +00:00
Andres Sanchez
24ecb92621 Fixed typo in the instructions for Pop_OS installation commands 2023-01-15 11:41:10 -05:00
Luke Jones
a811417f5d Merge branch 'fluke/aura_advanced' into 'main'
Fluke/aura advanced

See merge request asus-linux/asusctl!151
2023-01-15 09:36:03 +00:00
Luke D. Jones
b012a01cad Update deps, prep RC 2023-01-15 22:27:44 +13:00
Luke D. Jones
e6a9c88695 RCC: Adjust check for dgpu status change 2023-01-11 18:17:45 +13:00
Luke Jones
048a7afa55 Merge branch 'fluke/aura_advanced' into 'main'
Convert repeated code in config-traits to a macro

See merge request asus-linux/asusctl!149
2023-01-09 10:32:54 +00:00
Luke D. Jones
53b854ef6d Convert repeated code in config-traits to a macro 2023-01-09 23:19:29 +13:00
Luke Jones
fac635d07d Merge branch 'fluke/aura_advanced' into 'main'
Fluke/aura advanced

See merge request asus-linux/asusctl!148
2023-01-08 09:28:23 +00:00
Luke D. Jones
9cc62d63c9 Add checks to rename configs if required 2023-01-08 22:00:32 +13:00
Luke D. Jones
ab3007d53d daemon-user: refactor config files 2023-01-08 21:23:16 +13:00
Luke D. Jones
00839aaa6f Refactor config_trait crate and add doc comment examples 2023-01-08 20:41:17 +13:00
Luke D. Jones
5133d398eb Add extra doc comments to config-trait 2023-01-07 21:20:53 +13:00
Luke D. Jones
90b711c7b9 Break config-traits out in to crate 2023-01-07 20:46:00 +13:00
Luke D. Jones
ea5e5db490 ROGCC: add note re: aura in gui 2023-01-07 12:02:58 +13:00
Luke D. Jones
ef6ca9e51e Add support for GL703GE keyboard layout 2023-01-07 11:56:56 +13:00
Luke D. Jones
022a144705 Fix profile controller not detecting if platform_profile is changed
Closes #313
2023-01-07 11:45:01 +13:00
Luke Jones
8011ba3009 Merge branch 'fluke/config-traits' into 'main'
Fluke/config traits

See merge request asus-linux/asusctl!147
2023-01-06 06:57:07 +00:00
Luke D. Jones
d93b870726 Split fan-curve config to own file 2023-01-06 19:47:42 +13:00
Luke D. Jones
e4f79a3e6f Config files use generic traits 2023-01-06 12:03:12 +13:00
Luke Jones
54273cfb60 Merge branch 'main' into 'main'
Parameter fix for 'asusctl bios --help' (asus-linux/asusctl#299)

See merge request asus-linux/asusctl!146
2023-01-05 07:11:12 +00:00
Luke D. Jones
0dd4b2d6b5 Update readme with popos build instructions
Closes #302
2023-01-05 20:08:39 +13:00
Luke D. Jones
a2d850bbcb Update readme with new build requirements 2023-01-05 20:06:17 +13:00
Luke D. Jones
19f82493de Better config fie handling for the asusd daemon
Should address #304
2023-01-05 19:56:51 +13:00
Luke D. Jones
cbce854d1b Format 2023-01-04 09:34:56 +13:00
Luke D. Jones
ee0600d50d Adjust service file 2023-01-03 20:21:14 +13:00
Luke D. Jones
3d145ab9bd Slightly adjust keyboard widget 2023-01-03 20:21:14 +13:00
Luke D. Jones
1cbffedaeb Advanced Aura feature
Groundwork for 'advanced' aura modes
Add single zone + Doom light flash
Fix mocking for ROGCC
Better prepare & change to mapping of keyboard layouts to models and functions
Refactor and begin using new key layout stuff
Enable first arg to rogcc to set layout in mocking feature mode
Complete refactor of key layouts, and to RON serde
2023-01-03 20:21:11 +13:00
Luke D. Jones
e3ecaa92bd Add disable_nvidia_powerd_on_battery option 2023-01-03 20:17:52 +13:00
Luke D. Jones
067738b94f Fix pipeline 2022-12-28 21:34:16 +13:00
Luke D. Jones
29b22cd18e Fix incorrect stop/start order of nvidia-powerd on AC plug/unplug 2022-12-28 21:30:29 +13:00
Luke D. Jones
c2aa81bfe3 asusd: fixing a blocking op 2022-12-25 22:22:52 +13:00
mclang
5e9c612269 Fixes 'asusctl bios --help' (issue #299) 2022-12-19 20:33:44 +02:00
Luke D. Jones
8dcb209026 ROGCC: Don't notify user if changing to same mux mode 2022-12-10 21:42:52 +13:00
Luke D. Jones
bdb6c5b2ff Prep 4.5.6 release 2022-12-10 21:08:52 +13:00
Luke D. Jones
a318fbceec asusd: check if nvidia-powerd enabled before toggling 2022-12-10 21:05:27 +13:00
Luke D. Jones
8feacf863a asusd: Very basic support for running a command on AC/Battery switching 2022-12-10 20:51:00 +13:00
Luke D. Jones
0c62582515 ROGCC: Very basic support for running a command on AC/Battery switching 2022-12-10 20:17:45 +13:00
Luke D. Jones
3c575e4d2a ROGCC: Minor correction to tray menu 2022-12-10 19:37:20 +13:00
Luke D. Jones
dbfd73da5e ROGCC: Better handle the use of GPU MUX without supergfxd 2022-12-10 19:30:30 +13:00
Luke D. Jones
b1ee449b97 Adjust profile task to help TUF laptops notify 2022-12-09 10:03:45 +13:00
Luke D. Jones
245c035dc9 Fix tasks not always running correctly on boot/sleep/wake/shutdown 2022-12-08 20:12:55 +13:00
Luke D. Jones
07daa0df61 Fix: ROGCC: show option for LED notifications 2022-12-08 16:27:00 +13:00
Luke D. Jones
c7893b16f9 Fix: ROGCC: Remove unwrap causing panic on main thread
Closes #293
2022-12-08 11:14:01 +13:00
Luke Jones
8e8681c190 Merge branch 'main' into 'main'
add led modes for FX506HC

See merge request asus-linux/asusctl!144
2022-12-07 20:29:23 +00:00
HerrWinfried
b26c6a55f0 add led modes for FX506HC 2022-12-07 11:41:49 +00:00
Luke D. Jones
93d472fe74 Use correct defaults for GfxMode and GfxPower 2022-12-07 12:31:52 +13:00
Luke D. Jones
5469c73f11 Adjust gitlab pipeline to ignore checks for tags 2022-12-07 11:55:09 +13:00
Luke D. Jones
ad95765954 Add missing files 2022-12-07 11:50:17 +13:00
Luke D. Jones
e42a5bc3e9 ROGCC: don't require supergfxd to be running
Prep fixes for new tag and release
2022-12-07 11:47:27 +13:00
Luke D. Jones
28347e87eb Prep new minor release 2022-12-06 20:10:03 +13:00
Luke D. Jones
b34cb672c3 Fix: ROGCC: log and show more errors on startup 2022-12-06 14:28:35 +13:00
Luke D. Jones
559ddc9a22 Fix: ROGCC: remove unused arg in fan curve widget 2022-12-06 10:08:11 +13:00
Luke D. Jones
a8c014881f Version bump for RC 2022-12-06 09:48:24 +13:00
Luke D. Jones
f417032ed9 Fix: ROGCC: apply changes to correct fan curve profile
The fan curve profile changes were applying to the currently *active*
profile and not the GUI selected profile being changed. Fixed.

Also clarify the buttons for fan curve apply.
2022-12-06 09:47:48 +13:00
Luke D. Jones
616fb3aea6 chore: cranky cleanups 2022-12-05 20:31:39 +13:00
Luke D. Jones
6e6e057995 Update changelog 2022-12-05 19:44:50 +13:00
Luke D. Jones
085e63ebab Merge commit 'fdadffcdde82' because of borked HEAD after pull 2022-12-05 19:44:08 +13:00
Luke D. Jones
fdadffcdde Fix: ROGCC: Correctly deny badly formed fan graphs
Closes #286
2022-12-05 19:40:00 +13:00
Luke Jones
5f51527dd7 Merge branch 'piivanov-main-patch-89025' into 'main'
Add led modes for G713RM

See merge request asus-linux/asusctl!143
2022-12-04 20:53:46 +00:00
Peter Ivanov
39525980a0 Add led modes for G713RM 2022-12-04 17:39:32 +00:00
Luke D. Jones
83a0b570e0 Cause great pain to self with cargo-deny + cargo-cranky 2022-12-04 22:10:08 +13:00
Luke D. Jones
2bfbce36b0 Bump dependencies 2022-12-04 22:09:28 +13:00
Luke D. Jones
2705b08dca Cause great pain to self with cargo-deny + cargo-cranky 2022-12-04 21:49:47 +13:00
Luke D. Jones
2fca7a09c4 bump dependencies 2022-12-04 20:16:33 +13:00
Luke Jones
ef0da62c55 Merge branch 'maxbachmann-main-patch-99498' into 'main'
add led modes for G513RM

See merge request asus-linux/asusctl!141
2022-12-04 01:48:10 +00:00
maxbachmann
9dab120bcf add led modes for G513RM 2022-12-03 22:03:35 +00:00
Luke D. Jones
14bf07ba79 Version bump for dep updates 2022-12-02 16:39:46 +13:00
Luke D. Jones
e76d01eaed Update dependencies 2022-12-02 16:37:33 +13:00
Luke Jones
072a066f28 Merge branch 'fixed_readme_dependency_list_for_fedora' into 'main'
rust/cargo is also needed

See merge request asus-linux/asusctl!140
2022-12-01 20:11:39 +00:00
A. Binzxxxxxx
165c6f8ab3 rust/cargo is also needed 2022-12-01 20:06:28 +00:00
Luke Jones
5728a9af62 Update README.md 2022-11-22 21:54:51 +00:00
Luke Jones
17a880b2c5 Merge branch 'main' into 'main'
Fix VivoBook detection

See merge request asus-linux/asusctl!139
2022-11-20 19:48:29 +00:00
RushingAlien
6ba9b9d75d Fix VivoBook detection 2022-11-19 22:06:34 +07:00
Luke Jones
eb1f6c83ce Merge branch 'fix-gitlab-ci' into 'main'
Fix GitLab CI

See merge request asus-linux/asusctl!138
2022-11-16 20:06:06 +00:00
Herohtar
af653ea405 Don't install unnecessary packages 2022-11-16 12:26:14 -06:00
Herohtar
bc13891cdf Install required libgtk-3-dev package 2022-11-16 12:25:29 -06:00
Luke D. Jones
aad4dc909e Bump version 2022-11-16 20:33:23 +13:00
Luke D. Jones
ad79adcbfa ROGCC: splatter log messages everywhere. Rename state control 2022-11-16 20:32:11 +13:00
Luke D. Jones
73b1a7050a ROGCC: Make zbus notifications fully manage pagestates 2022-11-15 22:26:17 +13:00
Luke D. Jones
762bfea102 ROGCC: share PageState so tray can use it. zbus notifs update this 2022-11-15 11:12:41 +13:00
Luke D. Jones
b41fdf5cfe ROGCC: add status for dgpu, charge ctl, panel-od to systray 2022-11-14 11:05:52 +13:00
Luke D. Jones
bf13ebebd3 Set tray icon after init 2022-11-13 21:00:33 +13:00
Luke D. Jones
3a73e3a526 Try to prevent tray loop stalling 2022-11-13 12:52:52 +13:00
Luke D. Jones
1211400d7b 4.5.1-RC1 2022-11-11 20:13:00 +13:00
Luke D. Jones
ff9edb9876 Enable system tray status for dGPU and actions 2022-11-11 20:09:43 +13:00
Luke D. Jones
20f8251dd3 Adjust FA506IE led mode match to FA506I 2022-11-10 09:14:17 +13:00
Luke Jones
902dfed67c Merge branch 'add-asus-tuf-gaming-a15-led-modes' into 'main'
Add led_data for 2022 ASUS TUF Gaming A15 FA506IE

See merge request asus-linux/asusctl!137
2022-11-09 20:12:04 +00:00
Luke D. Jones
5e08b4416d Bump version 2022-11-10 09:11:52 +13:00
Herohtar
44c3ab7294 Add led_data for 2022 ASUS TUF Gaming A15 FA506IE 2022-11-09 12:03:23 -06:00
Luke D. Jones
be40474f79 Update app icons 2022-11-09 21:47:41 +13:00
Luke Jones
3654da2ff8 Merge branch 'tuxfanou/building_opensuse' into 'main'
Add openSUSE requirements to build asusctl

See merge request asus-linux/asusctl!136
2022-11-08 20:20:46 +00:00
Luke Jones
60bbad4ab6 Merge branch 'feat-add-vivobook-family' into 'main'
Add Vivobook to asusd rules

See merge request asus-linux/asusctl!135
2022-11-08 20:19:00 +00:00
Sarang S
0a59d5c041 Add Vivobook to asusd rules 2022-11-08 20:19:00 +00:00
Stéphane Burdin
1506fc44d3 Add openSUSE requirements to build asusctl 2022-11-08 16:14:53 +01:00
Luke D. Jones
aad31610f2 Add missing file 2022-11-08 22:03:42 +13:00
Luke D. Jones
a6fe7645e9 Tray icons 2022-11-08 21:55:09 +13:00
Luke D. Jones
4f8745ae19 Prep release 4.5.0 2022-11-07 21:36:28 +13:00
Luke D. Jones
5f4e950819 Update deps. Fixes to runtime 2022-11-07 09:47:15 +13:00
Luke D. Jones
efc752cce6 ROGCC: Use tokio instead of smol 2022-11-07 09:00:46 +13:00
Luke D. Jones
37553a5fdd Remove some dbg! statements 2022-11-06 22:28:00 +13:00
Luke D. Jones
cd5a85a843 Clarify gpu mux notif 2022-11-06 22:17:46 +13:00
Luke D. Jones
7385844a9b Fix rogcc not closing when run-in-background 2022-11-06 21:58:33 +13:00
Luke D. Jones
0b71104833 Fix rog-control-center notifs 2022-11-06 15:21:43 +13:00
Luke D. Jones
688e3a7358 Send signals using the correct context for each 2022-11-06 12:48:19 +13:00
Luke D. Jones
58ff566d65 Fix inclusion of supergfxctl lib 2022-11-04 21:31:45 +13:00
Luke D. Jones
1332ac803c Add notification of dGPU state change 2022-11-04 21:29:47 +13:00
Luke D. Jones
ba1d3f045d Add missing file 2022-10-11 22:25:49 +13:00
Luke D. Jones
e0ed52092a Refined AC monitoring 2022-10-11 22:13:54 +13:00
Luke D. Jones
921637f979 Make some ledmodes more generic matched across models 2022-10-10 13:19:15 +13:00
Luke D. Jones
f6498337fe RCC: disable vsync due to NoAvailablePixelFormat error: 2022-10-04 11:37:23 +13:00
Luke D. Jones
3a640a3269 Bump rc version 2022-10-01 14:57:49 +13:00
Luke D. Jones
e938f1f9ec Minor fixes to attr writes 2022-10-01 14:57:25 +13:00
Luke D. Jones
600d0ae3d9 Clippy run 2022-09-30 15:10:56 +13:00
Luke D. Jones
8569edf684 Try official latest docker image 2022-09-29 18:17:28 +13:00
Luke D. Jones
52af4ad2b2 Use 'latest' rustdocker image 2022-09-29 18:06:54 +13:00
Luke D. Jones
cde1b4f252 Shift all deps to workspace versioning 2022-09-29 17:08:28 +13:00
Luke Jones
2a4754cfc4 Merge branch 'ledmodes_for_rogflowx16' into 'main'
Added LED modes for ROG Flow X16

See merge request asus-linux/asusctl!134
2022-09-27 20:05:12 +00:00
Rino
51c97fa350 Added LED modes for ROG Flow X16 2022-09-27 12:44:49 +00:00
Luke D. Jones
c968dce009 Cleanup notifications some 2022-09-24 18:44:10 +12:00
Luke Jones
b2b6707f2e Merge branch 'fluke/inotify' into 'main'
Fluke/inotify

See merge request asus-linux/asusctl!133
2022-09-24 02:39:44 +00:00
Luke D. Jones
7939b00aa3 Check inotify paths are valid. Add dgu/egpu/ac_online checks 2022-09-24 14:34:15 +12:00
Luke D. Jones
30550aaa91 Further improve the daemon controller pattern and reduce cloned code 2022-09-23 20:07:43 +12:00
Luke D. Jones
7ea1f41286 Convert chunk of daemon to use async mutex 2022-09-23 10:50:09 +12:00
Luke D. Jones
9608d190b9 Use tokio in asusctl 2022-09-22 22:36:16 +12:00
Luke D. Jones
3b9cf474a7 inotify relies on tokio, so a switch is required.. 2022-09-22 12:55:15 +12:00
Luke D. Jones
283cb7e589 Previous inotify macro was blocking. Needs async closures... 2022-09-21 22:41:24 +12:00
Luke D. Jones
5d87747d96 Is smol blocking or inotify blocking it? 2022-09-21 22:17:55 +12:00
Luke D. Jones
56285916cd daemon: inotify for panel_od and gu_mux_mode 2022-09-21 19:04:28 +12:00
Luke D. Jones
a44a1bfa89 Add GU603Z to ledmodes 2022-09-20 21:02:58 +12:00
Luke D. Jones
0c97cf710d Trial single inotify test 2022-09-20 20:57:39 +12:00
Luke D. Jones
62c7338b2d Use loops to ensure settings apply where a mutex is tried 2022-09-15 13:29:00 +12:00
Luke Jones
af24623178 Merge branch 'zephyrus-m16-ledmodes' into 'main'
Add ledmodes for 2021 Zephyrus M16 models

See merge request asus-linux/asusctl!132
2022-09-14 04:52:47 +00:00
Albert Geantă
facb7f7f49 Add ledmodes for 2021 Zephyrus M16 models 2022-09-13 11:05:05 +03:00
Luke D. Jones
e38ab624e9 Add libfontconfig1-dev to CI env 2022-08-29 21:18:43 +12:00
Luke D. Jones
d76cb3b95a Minor update to changelog 2022-08-29 21:07:27 +12:00
Luke D. Jones
910f529a9b Release 4.4.0 2022-08-29 21:04:45 +12:00
Luke D. Jones
7583d070d3 daemon: add check to avoid accidental use of TUF led control 2022-08-29 20:53:14 +12:00
Luke D. Jones
1f85e30e42 Add CLI for 0x19b6 Lid LED 2022-08-29 18:17:19 +12:00
Luke D. Jones
d1bdf4dc7e rog-aura: Add lid zone 2022-08-29 17:09:26 +12:00
Luke D. Jones
79b108ceb7 rog-gui: don't reset selection when enable fan-curve 2022-08-29 13:44:59 +12:00
Luke D. Jones
7d14e8d900 rog-gui: add reset-curve button 2022-08-29 13:27:25 +12:00
Luke D. Jones
493d61cf19 rog-profiles: fixup populating default curves if none 2022-08-29 13:27:25 +12:00
Luke D. Jones
fb08d83999 rog-gui: sort fan curve by name 2022-08-29 13:27:25 +12:00
Luke Jones
71241b7127 Merge branch 'new-hyperlink' into 'main'
Changed hyperlink from achived code

See merge request asus-linux/asusctl!131
2022-08-28 06:18:53 +00:00
Alex carter
09963534d8 Changed hyperlink from achived code 2022-08-28 15:20:00 +10:00
Luke D. Jones
64322044ac rog-aura: tested effects on TUF, works 2022-08-27 22:30:57 +12:00
Luke D. Jones
1a132d847f Update readme 2022-08-27 21:01:17 +12:00
Luke D. Jones
952a974e83 Bump various versions 2022-08-27 20:53:59 +12:00
Luke D. Jones
ebbfa58a76 rog-aura: Add flicker effect 2022-08-27 20:52:43 +12:00
Luke D. Jones
414d610bd2 Test battery search 2022-08-27 11:18:15 +12:00
Luke D. Jones
bff98ddf7b power: rc4, remove energy_full_design check 2022-08-26 21:09:52 +12:00
Luke D. Jones
97481cd45e rog-aura: add per-zone effects 2022-08-26 18:29:24 +12:00
Luke Jones
4f39c01139 Merge branch 'AlexanderRavenheart-main-patch-32476' into 'main'
Update asusd-ledmodes.toml: added board name G513RC

See merge request asus-linux/asusctl!130
2022-08-25 20:43:30 +00:00
Luke D. Jones
40987ecd5d rog-aura: add basic per-key support 2022-08-25 21:45:36 +12:00
Luke D. Jones
f378c54815 Remove println from example 2022-08-25 18:29:53 +12:00
Luke D. Jones
a8a99ac1d1 rog-aura: reorganise per-key effects 2022-08-25 18:25:04 +12:00
Luke D. Jones
503aa20257 rog-aura: don't start effect on red 2022-08-25 14:11:31 +12:00
Luke D. Jones
8c67836650 Implement simple 'breathe' per-key effect 2022-08-25 14:08:53 +12:00
Luke D. Jones
3fc839820e Version bump 2022-08-24 22:29:56 +12:00
Luke D. Jones
0ef524a94b rog-aura: bringup the per-key LED stuff again 2022-08-24 22:01:13 +12:00
Alexandru Rudi
f8cfacda47 Update asusd-ledmodes.toml: added board name G513RC 2022-08-24 04:28:45 +00:00
Luke D. Jones
f3876100ae rog-platform: Add extra check types to find battery
Closes #243
2022-08-24 10:11:32 +12:00
Luke D. Jones
fa1feaf9d9 rog-platform: additional check against manufacturer attr
Should close #242
2022-08-22 09:01:08 +12:00
Luke D. Jones
45641c928d Rename all instances of dgpu_only to gpu_mux 2022-08-21 21:39:01 +12:00
Luke D. Jones
eba9dc8a52 daemon: update an old log comment. Don't reload panel_od if not available
Closes #242
2022-08-21 21:28:52 +12:00
Luke D. Jones
a32527d1df Doc updates 2022-08-21 20:23:55 +12:00
Luke D. Jones
1f697b5ff1 daemon: Vastly improved task creation 2022-08-21 20:15:36 +12:00
Luke D. Jones
92009ef96c profiles: error if fan curve parse is less than 8
Closes #225
2022-08-20 22:05:22 +12:00
Luke D. Jones
3fe5896596 daemon: fix keyboard brightness setting
Closes #241
2022-08-20 21:42:18 +12:00
Luke D. Jones
f8cdde2adf rog-platform: add power (basics)
- Refactor the macros
- Add inotify creator for each attribute
2022-08-20 21:07:34 +12:00
Luke Jones
033f2141ef Merge branch 'alex39-main-patch-50587' into 'main'
Update asusd-ledmodes.toml - added G713RS

See merge request asus-linux/asusctl!129
2022-08-17 00:37:47 +00:00
AlexEdimensionz
f86bab6f8c Update asusd-ledmodes.toml - added G713RS
This is my laptop model and i confirm that "G713RS" is in the correct config group (tested all the modes)
2022-08-17 00:20:25 +00:00
Luke D. Jones
4951bce961 Add missing files :( 2022-08-17 11:16:19 +12:00
Luke D. Jones
fb92d65fa0 Prep for new release 2022-08-17 10:32:24 +12:00
Luke D. Jones
24fa075a44 Extend GpuMode to include other modes 2022-08-12 22:10:49 +12:00
Luke D. Jones
a0f7cf3acd Rename RogBios bits to Platform. Better GPU MUX support. 2022-08-12 21:51:04 +12:00
Luke D. Jones
d35707f2e4 Merge rog-supported in to rog-platform 2022-08-12 17:45:29 +12:00
Luke Jones
b20bde8116 Merge branch 'fluke/kernel-patch-leds' into 'main'
Create rog-platform, refactor rogcc ipc-file handling

See merge request asus-linux/asusctl!128
2022-08-12 04:40:59 +00:00
Luke D. Jones
308fba9413 Create rog-platform, refactor rogcc ipc-file handling
- Create new rog-platform crate to manage all i/o in a universal way
  + kbd-led handling
  + platform handling (asus-nb-wmi)
  + hidraw
  + usbraw
- Refactor how ROGCC handles IPC for background open, run-in-bg
2022-08-12 15:22:06 +12:00
Luke D. Jones
45268bfb2b Add note and screenshots of GUI 2022-08-06 09:36:47 +12:00
Luke D. Jones
004982cea7 ROGCC: group fan profile buttons with cpu/gpu buttons with enable/disable 2022-08-04 20:25:15 +12:00
Luke D. Jones
5ab24a624e Version bump 2022-08-03 09:52:37 +12:00
Luke D. Jones
700633e080 ROGCC: Remove power setting from correct array 2022-08-03 09:48:00 +12:00
Luke D. Jones
773c9902a5 Release 4.3.3 2022-08-02 15:11:02 +12:00
Luke D. Jones
e05d5bd143 Version bump. Add early-error display 2022-08-02 15:09:25 +12:00
Luke D. Jones
3e244d7d3d ROGCC: effect visuals. daemon: support TUF RGB 2022-08-02 14:25:27 +12:00
Luke D. Jones
ba4589f986 ROGCC: effect visual test 2022-08-02 09:27:10 +12:00
Luke Jones
083134fc73 Merge branch 'support-g713rw' into 'main'
Add G713RW to asusd-ledmodes.toml

See merge request asus-linux/asusctl!125
2022-07-31 21:27:43 +00:00
Luke Jones
3cc04fba60 Merge branch 'danielphan2003-main-patch-53505' into 'main'
Use INSTALL_DATA for toml and gif files

See merge request asus-linux/asusctl!127
2022-07-31 21:27:17 +00:00
Daniel Phan
3a00e4f1a3 Use INSTALL_DATA for toml and gif files 2022-07-31 15:34:25 +00:00
Luke D. Jones
eb78fb613c New udev rules to work with both TUF and ROG 2022-07-30 23:08:47 +12:00
Luke D. Jones
d0b9aee85a daemon: Re-enable aura control for TUF
Closes #228
2022-07-30 20:52:43 +12:00
Luke Jones
3e94ef05fb Merge branch 'fix/anime-brightness-ignores-first-6-leds' into 'main'
Fix brightness setting ignoring the first 6 leds

Closes #230

See merge request asus-linux/asusctl!126
2022-07-29 21:15:06 +00:00
Ivan Voskoboinyk
fbb025875b Fix brightness setting ignoring the first 6 leds
Fixes #230
2022-07-29 15:29:16 +00:00
Yevhen Kolomeiko
ae816bd13c Add G713RW to asusd-ledmodes.toml 2022-07-29 11:41:19 +00:00
Luke D. Jones
14f0693511 rog-aura: add gap between numpad on gl504 2022-07-29 19:22:47 +12:00
Luke D. Jones
de7fb4a942 ROGCC: use the correct colourspace for colour picker 2022-07-29 18:59:52 +12:00
Luke D. Jones
4164b4645d ROGCC: split keyboard layout into widget 2022-07-29 16:08:55 +12:00
Luke D. Jones
649b14fd0d rog-aura: stand-off the rog row 2022-07-29 16:03:39 +12:00
Luke D. Jones
6d97ef13a1 rog-aura: adjustment of layouts and key sizes 2022-07-29 15:56:03 +12:00
Luke D. Jones
7abad979c8 rog-aura: adjustment of layouts and key sizes 2022-07-29 15:35:03 +12:00
Luke D. Jones
0ec1574219 rog-aura: Cleanup layouts, add gl504_US.toml 2022-07-29 12:07:16 +12:00
Luke D. Jones
03042dd5c3 Remove accidental board name test 2022-07-29 11:26:38 +12:00
Luke D. Jones
3330e4973f rog-aura: add proper labels for keys via &str into 2022-07-29 11:15:37 +12:00
Luke D. Jones
5e06aeabe9 rog-aura: fix up G533 layout 2022-07-29 10:54:59 +12:00
Luke D. Jones
e99d8766fc ROGCC: rog-aura: Keyboard layout templates and definitions
This also removes shell completitions as these are not maintained.
2022-07-29 09:19:49 +12:00
Luke D. Jones
8f65b7e334 ROGCC: add enable/disable aura options depending on mode 2022-07-27 11:39:55 +12:00
Luke D. Jones
5a54b830bf ROGCC: style change 2022-07-26 22:35:51 +12:00
Luke D. Jones
85e08510f7 ROGCC: style change 2022-07-26 22:20:00 +12:00
Luke D. Jones
d56eeb7fb2 ROGCC: split widgets from pages 2022-07-26 21:39:30 +12:00
Luke D. Jones
bbc520a7f2 Update deps 2022-07-26 19:30:50 +12:00
Luke D. Jones
10e43c64ca ROGCC: rename config file 2022-07-26 19:16:46 +12:00
Luke D. Jones
38be25174a Add verbose output for fan-curve detection. Add mocking to GUI.
asusd: Verbose output of fan-curves on startup
ROGCC: Try to mock more of GUI state
2022-07-26 18:59:21 +12:00
Luke D. Jones
2584d69930 Update deps 2022-07-25 21:38:00 +12:00
Luke D. Jones
523f39cf9c Version bump for RC 2022-07-25 21:34:33 +12:00
Luke D. Jones
669760223e Clean up erroneously included files 2022-07-25 21:32:58 +12:00
Luke D. Jones
71ec13fa9f ROGCC: Attempt to add LED brightness 2022-07-25 21:21:32 +12:00
Luke D. Jones
409528b286 ROGCC: Better control of notifs, add panel_od 2022-07-25 20:55:30 +12:00
Luke D. Jones
17df3cf01d Add rog-control-center to the workspace 2022-07-25 16:43:48 +12:00
Luke D. Jones
808a1d2470 Fix misnamed led dbus method 2022-07-25 14:22:29 +12:00
Luke D. Jones
840c500b5e Switch a keyboard prod_id to enum 2022-07-25 14:07:29 +12:00
Luke D. Jones
42dc360d16 Bump daemon version 2022-07-25 12:43:17 +12:00
Luke D. Jones
f6183597c9 Trial BTreeMap<AuraModeNum, AuraEffect> return for led dbus 2022-07-25 10:26:47 +12:00
Luke D. Jones
79a45c4f10 Add to/from [f32;3] for Colour] 2022-07-25 09:51:25 +12:00
Luke D. Jones
19370215c0 Cleanup 2022-07-24 20:55:09 +12:00
Luke D. Jones
030dd661b8 Switch zbus led_mode to return AuraModeNum 2022-07-24 20:45:20 +12:00
Luke D. Jones
1fc12d9855 Make CurveData members public 2022-07-24 10:50:28 +12:00
Luke D. Jones
6c1b2b70ea Make FanCurveSet members public 2022-07-24 10:47:40 +12:00
Luke D. Jones
23f9af35bf Add Hash derive to Profile 2022-07-24 09:43:22 +12:00
Luke D. Jones
526626b80c Minor tweaks on derives 2022-07-24 09:28:00 +12:00
Luke Jones
10eaaac54b Merge branch 'sova/G713IC-led-support' into 'main'
Add LED support for G713IC

See merge request asus-linux/asusctl!124
2022-07-21 12:39:43 +00:00
SoVa
901a3ddcc9 Add LED support for G713IC 2022-07-21 14:18:33 +02:00
Luke Jones
e6ebf72a11 Merge branch 'main' into 'main'
Fix some typos.

See merge request asus-linux/asusctl!123
2022-07-21 07:59:16 +00:00
Luke D. Jones
cd7e748c88 Prep new release 2022-07-21 19:36:17 +12:00
成超(Cheng Chao)
a313359ef6 Fix some typos. 2022-07-21 12:46:44 +08:00
Luke Jones
f222eef6b7 Update CHANGELOG.md 2022-07-21 03:40:04 +00:00
Luke Jones
e6f3aeb851 Merge branch 'fluke/multi-led-power' into 'main'
Make LED power more universal

Closes #219

See merge request asus-linux/asusctl!122
2022-07-21 03:39:11 +00:00
Luke D. Jones
22605e57cc Properly set full defaults for LED power 2022-07-21 14:56:30 +12:00
Luke D. Jones
02fb7addf4 Make LED power more universal
Closes #219
2022-07-21 14:48:16 +12:00
Luke Jones
bdbb403a0e Merge branch 'fluke/errors' into 'main'
Improve error handling in some cases

See merge request asus-linux/asusctl!121
2022-07-20 09:01:55 +00:00
Luke D. Jones
7a8bede92f Return error if a pixel-gif is larger than the anime-display dimensions 2022-07-20 20:52:03 +12:00
Luke D. Jones
a71a40b509 Make rog-anime more tolerent of faults 2022-07-20 20:17:43 +12:00
Luke D. Jones
42fc5a5392 Minor doc comment change 2022-07-18 15:43:09 +12:00
Luke D. Jones
5017a0ea9b Add extra multizone test 2022-07-18 14:11:54 +12:00
Luke D. Jones
05f7b0060f Prep new release 2022-07-18 14:01:32 +12:00
Luke Jones
1043da5328 Merge branch 'fluke/multizone-defaults' into 'main'
Create defaults on missing zones

See merge request asus-linux/asusctl!120
2022-07-18 01:50:35 +00:00
Luke D. Jones
959ad35afa Create defaults on missing zones 2022-07-18 13:40:42 +12:00
Luke Jones
1e10255d01 Merge branch 'fluke/multizone-fixes' into 'main'
Fluke/multizone fixes

See merge request asus-linux/asusctl!119
2022-07-17 10:02:32 +00:00
Luke D. Jones
c72693bc53 Fix test for CI 2022-07-17 22:02:01 +12:00
Luke D. Jones
2297aad5e5 Fix test 2022-07-17 21:49:15 +12:00
Luke D. Jones
f39c0db680 Add more support detection for bios/system level components 2022-07-17 21:02:39 +12:00
Luke D. Jones
23353c77f3 Add panel_od support 2022-07-17 20:31:47 +12:00
Luke D. Jones
fee1486db6 Correctly save multizone config 2022-07-17 19:23:08 +12:00
Luke D. Jones
39c4253b24 Add GA401I Anime support 2022-07-17 15:08:18 +12:00
Luke D. Jones
84e924f46a Add doc comments for bytes of 0x1866 power control 2022-07-16 22:52:36 +12:00
Luke D. Jones
43364398b4 Add LED support for GX703HS
Closes #207
2022-07-16 15:11:37 +12:00
Luke D. Jones
3f09f221f4 Bump versions 2022-07-16 15:03:42 +12:00
Luke Jones
4ed922154b Merge branch 'validate-anime-brightness' into 'main'
Enforce valid image brightness in daemon and asusctl

See merge request asus-linux/asusctl!118
2022-07-16 03:00:22 +00:00
I Al Istannen
c0e36295b7 Enforce valid image brightness in daemon and asusctl 2022-07-16 03:00:22 +00:00
Luke D. Jones
ef04549c8e Bump versions 2022-07-16 13:45:23 +12:00
Luke D. Jones
a117c300d5 Add support for /etc/asusd/asusd-user-ledmodes.toml 2022-07-16 13:40:57 +12:00
Luke D. Jones
6956f7dffc Re-enable cargo test in pipeline 2022-07-15 23:54:30 +12:00
Luke D. Jones
fe49913550 Updated changelog 2022-07-15 23:54:20 +12:00
Luke D. Jones
89ddade2a3 Updated changelog 2022-07-15 23:54:07 +12:00
Luke Jones
bcb3d53ade Merge branch 'readme_cargo' into 'main'
cargo added to installation

See merge request asus-linux/asusctl!115
2022-07-15 11:31:05 +00:00
Luke Jones
9ab9028d79 Merge branch 'fluke/ga402-anime' into 'main'
First pass of Anime update for new matrix display

See merge request asus-linux/asusctl!113
2022-07-15 11:30:28 +00:00
Luke Jones
8de6447562 Merge branch 'fluke/ga402-anime' into 'fluke/ga402-anime'
AnimeImage patch for GA402

See merge request asus-linux/asusctl!116
2022-07-15 11:23:43 +00:00
I-Al-Istannen
2512cea19d Slightly adjust G402 scaling, add some more documentation 2022-07-15 13:12:34 +02:00
Luke D. Jones
eabe78af71 tmp 2022-07-15 23:00:01 +12:00
Luke D. Jones
16c4ee609e Add GA402 anime-matrix packet unit test 2022-07-15 20:40:16 +12:00
Luke D. Jones
37d586c5de Additional comments in animeimage 2022-07-15 20:38:07 +12:00
Luke D. Jones
e66847c263 Add commenting to AnimeImage to help with GA402 2022-07-15 20:37:30 +12:00
I-Al-Istannen
a2c8a226a4 Complete anime diagonal gif support for GA402 2022-07-15 20:37:30 +12:00
Luke D. Jones
f3f6fadfe2 Fix anime exampels 2022-07-15 20:37:30 +12:00
Luke D. Jones
ff76c356c5 First pass of Anime update for new matrix display
Co-authored with @I-Al-Istannen

Part of #189
2022-07-15 20:37:30 +12:00
Luke D. Jones
a22808aff3 Add note in cargo.toml re: lto 2022-07-15 10:21:11 +12:00
Luke D. Jones
f39fd6dfbb Use hashset in aura power config 2022-07-15 09:30:10 +12:00
Luke Jones
95598f2a76 Merge branch 'fluke/multizone' into 'main'
Multizone support plus rebuild of LED power control

Closes #213

See merge request asus-linux/asusctl!117
2022-07-14 11:20:22 +00:00
Luke D. Jones
535e104ccc Rebuild of LED power control 2022-07-14 23:05:33 +12:00
saswatasarkar13
522cee42e5 cargo added to installation 2022-07-14 14:57:04 +05:30
Luke D. Jones
51656dc13f Initial multizone fixup work 2022-07-14 15:09:28 +12:00
Luke D. Jones
abd412b5d5 Save and restore kb bright only on shutdown/sleep/boot/wak
Closes #213
2022-07-14 13:05:51 +12:00
Luke D. Jones
4d8c05cd92 Add more multizone support 2022-07-14 13:05:41 +12:00
Luke Jones
f2ca8081af Merge branch 'user.sv4.apps-main-patch-52927' into 'main'
Fan curve kernel requirement message update.

See merge request asus-linux/asusctl!112
2022-07-12 01:55:42 +00:00
User
7539011be5 Update main.rs 2022-07-09 10:41:29 +00:00
Luke D. Jones
5117427143 Add GA503R LED modes
Closes #205
2022-06-26 11:57:15 +12:00
Luke D. Jones
e95986b830 Update changelog 2022-06-24 23:12:04 +12:00
Luke D. Jones
5311972345 Set keyboard brightness on resume. Refactor some tasks 2022-06-24 23:09:45 +12:00
Luke D. Jones
967295fba7 Fixes to anime-matrix system thread handling 2022-06-21 23:29:44 +12:00
Luke D. Jones
5403c5fb4f Update changelog 2022-06-20 23:16:25 +12:00
Luke D. Jones
65986c3114 prep new release 2022-06-20 23:13:17 +12:00
Luke D. Jones
13a90b00f3 Adjust how thread exit is handled for anime controller 2022-06-20 22:43:12 +12:00
Luke Jones
2ee7fc9910 Merge branch '191-full-power-states-combinations' into 'main'
Combination for power state leds boot/sleep/all/keys/side LEDS

Closes #191

See merge request asus-linux/asusctl!111
2022-06-19 22:03:23 +00:00
mpiffault
a0a0efabbb Combination for power state leds boot/sleep/all/keys/side LEDS 2022-06-19 22:03:23 +00:00
Luke Jones
9a50278b98 Merge branch 'fluke/async-tasks' into 'main'
Fixes to tasks

See merge request asus-linux/asusctl!110
2022-06-12 03:42:09 +00:00
Luke D. Jones
9519a35e32 Fixes to tasks 2022-06-12 15:34:38 +12:00
Luke Jones
578d5fd541 Merge branch 'fix/199-multizone-commands-not-displayed' into 'main'
Fixes #199 multizone commands not displayed

Closes #199

See merge request asus-linux/asusctl!109
2022-06-12 03:32:11 +00:00
Martin Piffault
642bc5dda1 output multizone commands required 2022-06-07 22:31:53 +02:00
Martin Piffault
88274abdb5 init multizone_led_mode and per_key_led_mode from LaptopLedData 2022-06-07 22:30:37 +02:00
Luke Jones
aea65f5c5f Merge branch 'fluke/async-tasks' into 'main'
Re-enable notif for profile change

See merge request asus-linux/asusctl!108
2022-06-07 00:13:24 +00:00
Luke D. Jones
edfbfde13b Re-enable notif for profile change 2022-06-07 12:08:36 +12:00
Luke Jones
dcc676d60a Merge branch 'fluke/async-tasks' into 'main'
Added tasks for reload keyboard bright, and for charge control

See merge request asus-linux/asusctl!107
2022-06-06 23:53:41 +00:00
Luke D. Jones
561f61116c Added tasks for reload keyboard bright, and for charge control 2022-06-07 11:49:12 +12:00
Luke Jones
6a4594466b Merge branch 'fluke/async-tasks' into 'main'
Async tasks

See merge request asus-linux/asusctl!106
2022-06-06 13:00:10 +00:00
Luke D. Jones
af216ee08c Async tasks 2022-06-07 00:54:33 +12:00
Luke D. Jones
e493113450 update changelog 2022-06-06 18:25:27 +12:00
Luke D. Jones
74e1d5bdc4 Add brightness to anime zbus notif 2022-06-06 18:24:08 +12:00
Luke D. Jones
5c0ad3e590 Re-enable notification on anime power-state change 2022-06-06 18:18:35 +12:00
Luke D. Jones
6e872ecab9 Add diagonal-template.png to rog-anime/data/anime/custom/
Closes #163
2022-06-06 17:20:38 +12:00
Luke D. Jones
46a4cde77f Add G512 to LED support list
Closes #174
2022-06-06 17:02:41 +12:00
Luke D. Jones
fc7c444107 Add GU502LV LED support
Closes #187
2022-06-06 16:57:50 +12:00
Luke D. Jones
822438e0d2 Version bumps 2022-06-06 14:53:30 +12:00
Luke D. Jones
de43a37e9e Use smol async for daemon and daemon-user 2022-06-06 14:34:59 +12:00
Luke D. Jones
d4b2d2f403 Use smol async for asus-notify 2022-06-06 13:57:03 +12:00
Luke D. Jones
6e33eab136 Update anime examples 2022-06-06 13:11:54 +12:00
Luke D. Jones
1e4bc85fee Partial asusd-user update 2022-06-06 01:33:14 +12:00
Luke D. Jones
31fff75f08 Update more deps 2022-06-06 00:41:07 +12:00
Luke D. Jones
f0620154c8 Update changelog 2022-06-06 00:21:05 +12:00
Luke D. Jones
711aa1e4be Add support for GA402R
Closes #196
2022-06-06 00:14:28 +12:00
Luke D. Jones
854f2d75b3 Format 2022-06-06 00:09:23 +12:00
Luke D. Jones
a85e2f6130 Finalise zbus3 conversion 2022-06-06 00:08:59 +12:00
Luke Jones
bac2ba6f09 Merge branch 'mpiffault-main-patch-00521' into 'main'
Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QM

See merge request asus-linux/asusctl!103
2022-06-05 02:58:49 +00:00
Luke Jones
47e5270f9c Merge branch 'feat/side-leds-toggle-support' into 'main'
Adds support to enable/disable side leds #191

See merge request asus-linux/asusctl!104
2022-06-05 02:58:24 +00:00
Luke Jones
68cbf09e9f Merge branch 'fix/aura-help-options-display' into 'main'
Fixes all available led-mode commands not displaying with `asusctl led-mode --help`

See merge request asus-linux/asusctl!105
2022-06-05 02:54:31 +00:00
Martin Piffault
9f18c88153 fix all available options not being displayed in led-mode help 2022-06-04 14:47:40 +02:00
Martin Piffault
c6caafdcb7 adds support to enable/disable side leds 2022-05-31 17:00:21 +02:00
mpiffault
b22a3e1a59 Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QM 2022-05-30 08:06:26 +00:00
Luke Jones
b6934bbf63 Merge branch 'as/issue_176_1' into 'main'
Fix for fan_curve related integer divison bug

Closes #176

See merge request asus-linux/asusctl!102
2022-04-08 21:18:47 +00:00
Armas Spann
3cd6eb13a9 fixed interger division bug and related tests, as well as a comment bug 2022-04-07 01:16:06 +02:00
Luke Jones
272be2aaad Merge branch 'as/issue_176' into 'main'
fix for #176 - fancurve percentage check not handled correctly

Closes #176

See merge request asus-linux/asusctl!101
2022-04-05 21:37:23 +00:00
Armas Spann
99dd6ce77f fix for #176 - fancurve percentage check not handled correctly 2022-04-05 23:33:43 +02:00
Luke Jones
fc14455da4 Merge branch 'ankushmishra9-main-patch-66732' into 'main'
Fixed formatting of install instructions

See merge request asus-linux/asusctl!96
2022-02-07 22:59:34 +00:00
Luke Jones
26a52dae23 Merge branch 'main' into 'main'
add g513ic led

See merge request asus-linux/asusctl!94
2022-01-19 20:13:34 +00:00
Ankush Mishra
75864d33a6 Fixed formatting of install instructions 2022-01-19 17:57:06 +00:00
Luke Jones
63a97b6665 Merge branch 'main' into 'main'
fixed a small typo

See merge request asus-linux/asusctl!95
2022-01-15 20:51:52 +00:00
AlenPaulVarghese
21a37a3bb0 fixed a small typo 2022-01-14 18:49:15 +00:00
dada513
de586b5368 add g513ic led 2022-01-11 10:08:45 +00:00
Luke D. Jones
ba40c3f739 Update dependencies 2021-12-19 21:01:47 +13:00
Luke D. Jones
31eff037a2 Bump to version 4.0.7 2021-12-19 21:00:58 +13:00
Luke D. Jones
630dee0b2a Update notes in CLI tool 2021-12-19 20:57:50 +13:00
Luke Jones
9110f06ed5 Update README.md
Remove whitespace and rustup from fedora build section
2021-12-17 21:18:00 +00:00
Luke Jones
2b0eceaa9d Merge branch 'main' into 'main'
Update of README for building and installing

See merge request asus-linux/asusctl!93
2021-12-17 21:16:56 +00:00
Peter Ross
c96e1babe5 Update README.md 2021-12-16 15:23:08 +00:00
Peter Ross
9388cbde5d Update README.md 2021-12-16 15:16:35 +00:00
Luke D. Jones
e739cddd6a Update patch links 2021-12-04 16:04:56 +13:00
Luke Jones
8cee6e0fc4 Remove Ubuntu repo instructions 2021-11-14 21:51:56 +00:00
Luke Jones
bcf516afeb Merge branch 'sonnyp-main-patch-01923' into 'main'
Update kernel support for Linux 5.15

See merge request asus-linux/asusctl!88
2021-11-12 00:23:54 +00:00
Luke Jones
b0e3e81b7f Merge branch 'fix/platform-functions/profile-support' into 'main'
Fix incorrect power profile support validation.

See merge request asus-linux/asusctl!89
2021-11-12 00:23:22 +00:00
Luke Jones
ce6a1215a3 Merge branch 'LordVicky-main-patch-24845' into 'main'
Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QE

See merge request asus-linux/asusctl!90
2021-11-12 00:22:51 +00:00
LordVicky
f54c1dc7d0 Fix typo 2021-11-09 07:32:39 +00:00
LordVicky
43aaae8d47 Update asusd-ledmodes.toml to support Asus Rog Strix G15 G513QE 2021-11-09 07:28:57 +00:00
Alexander Narsudinov
ca463a2944 Fix incorrect power profile support validation.
Before this patch power profile support validation used wrong flag from PlatformProfileFunctions struct.
2021-11-07 15:11:31 +03:00
Sonny Piers
20e22589dc Update kernel support for Linux 5.15 2021-11-04 11:47:47 +00:00
Luke D. Jones
38d047cb8a Update changelog 2021-11-01 16:03:40 +13:00
Luke D. Jones
1d977199f3 Fix cli for bios/g-sync 2021-11-01 10:57:40 +13:00
Luke Jones
5041019d77 Merge branch 'fluke/anime-cli' into 'main'
Fluke/anime cli

See merge request asus-linux/asusctl!87
2021-10-30 20:28:36 +00:00
Luke D. Jones
aa3835d3b3 Bump versions 2021-10-31 09:24:07 +13:00
Luke D. Jones
678505811d Add additional anime cli commands for image types 2021-10-28 23:43:50 +13:00
Luke D. Jones
a925cbaed5 Bump version 2021-10-27 23:19:31 +13:00
Luke Jones
7d2201d873 Merge branch 'fluke/bugfixes' into 'main'
Add led modes for G513QR

Closes #144 and #143

See merge request asus-linux/asusctl!86
2021-10-27 10:18:31 +00:00
Luke D. Jones
c0c1608d44 Update deps 2021-10-27 23:15:25 +13:00
Luke D. Jones
7bc6c83a04 Check and pass error if charge limit not in 20-100 range
Closes #144
2021-10-27 23:04:44 +13:00
Luke D. Jones
3f0df82f2d Parse percentages in fan curve only if '%' provided otherwise range is 0-255 2021-10-27 22:42:32 +13:00
Luke D. Jones
328ff0251b Add led modes for G513QR
Closes #143
2021-10-27 22:35:48 +13:00
Luke Jones
c52582a413 Merge branch 'fluke/bugfixes' into 'main'
Bugfixes

Closes #139 and #140

See merge request asus-linux/asusctl!85
2021-10-02 07:34:55 +00:00
Luke D. Jones
3aa6eee306 Bugfixes
- Spawn tasks on individual threads
- Don't force a default of fan-curve on reload
- Add missing profile commands
- Begin obsoleting the graphics switch command in favour of supergfxctl
- Slim down the notification daemon to pure ASUS notifications

Bad behaviour in fan-curve new function that was forcing a re-init
to default on reload. Remove this and only save config again after
loading the config file and writing a curve (hidden side effect of
write is that a zeroed array is defaulted to read-from-system - this
needs to be changed too).

Closes #140, #139
2021-10-02 20:31:14 +13:00
Luke Jones
7d47faba0e Merge branch 'plasma-logout' into 'main'
Add kde logout prompt as fallback to gnome-session-quit

See merge request asus-linux/asusctl!82
2021-09-21 08:07:43 +00:00
Luke Jones
f6fb477898 Merge branch 'main' into 'main'
Updated asusd-ledmodes.toml with ROG Strix G713QM

See merge request asus-linux/asusctl!83
2021-09-21 08:06:59 +00:00
Abhijith M
8963960d4b Updated asusd-ledmodes.toml with ROG Strix G713QM 2021-09-21 02:09:53 +00:00
Janghyub Seo
ef973f676b Add kde logout prompt as fallback to gnome-session-quit 2021-09-19 02:13:11 +09:00
Luke D. Jones
812f9ea30e Add lock update 2021-09-16 22:38:09 +12:00
Luke Jones
ff843b1241 Merge branch 'main' into 'main'
Add G533QS to supported models

See merge request asus-linux/asusctl!81
2021-09-16 10:30:09 +00:00
George Dumitrescu
59e7af149d Add G533QS to supported models 2021-09-16 10:07:48 +03:00
Luke D. Jones
6f14c85287 Revert supergfxctl deps to git 2021-09-16 16:03:41 +12:00
Luke D. Jones
ac0dec4dbf Bump daemon version for release 2021-09-16 11:20:17 +12:00
Luke D. Jones
e3d192412e Bugfixes 2021-09-16 11:19:05 +12:00
Luke Jones
9fadb6db30 Merge branch 'necessary129-main-patch-69023' into 'main'
Add another Strix G17 model

See merge request asus-linux/asusctl!80
2021-09-15 00:06:31 +00:00
Shamil K
f8a1b71866 Add another Strix G17 model 2021-09-14 12:00:04 +00:00
Luke Jones
c0a55acba7 Merge branch 'main' into 'main'
Adding ROG Flow X13 to LED modes known devices

See merge request asus-linux/asusctl!79
2021-09-14 11:45:56 +00:00
Joseph Ferano
4f232de634 Adding ROG Flow X13 to LED modes known devices 2021-09-14 18:05:42 +07:00
Luke Jones
d351ebdaa0 Merge branch 'fluke/fan_curves_v13' into 'main'
Fluke/fan curves v13

See merge request asus-linux/asusctl!78
2021-09-14 02:55:51 +00:00
Luke D. Jones
ab195e1d84 Fan curve enablement
- Add CtrlProfileTask
- Add method to reset active profile curve to platform default
- Wrap the zbus methods for profiles + fan curves
- Enable CLI args for fan curves
- CLI mod and save curves
2021-09-14 14:52:15 +12:00
Luke D. Jones
7041d77256 Fix asusd-ledmodes.toml 2021-09-11 17:03:32 +12:00
Luke D. Jones
99dd052d54 Bump version in readme 2021-09-11 00:27:21 +12:00
Luke Jones
de9942609e Merge branch 'fluke/fan_curves_v9' into 'main'
Fluke/fan curves v9

See merge request asus-linux/asusctl!77
2021-09-10 12:26:14 +00:00
Luke D. Jones
b939a9d331 Fetch and store fan curve correctly 2021-09-11 00:25:46 +12:00
Luke D. Jones
0a565a7a5c Fleshing out functions and zbus controls 2021-09-08 23:33:42 +12:00
Luke D. Jones
bfaa478a4a Begin syncing changes with patch series 2021-09-07 20:20:37 +12:00
Luke Jones
f895a5623e Merge branch 'doc-ubuntu' into 'main'
Add ubuntu repo install commands

See merge request asus-linux/asusctl!76
2021-09-06 03:48:19 +00:00
Guy Sheffer
b7c869bd64 Add ubuntu repo install commands 2021-09-05 10:55:16 +03:00
Luke D. Jones
5f677bc3b9 Provide extra help tips. Update manual 2021-08-29 21:30:30 +12:00
Luke D. Jones
ccfadc2fcb Updates to asusctl cli app 2021-08-28 11:47:01 +12:00
Luke D. Jones
c6cc304a42 Clean up unwrap()'s. Print out info in asusctl if error 2021-08-28 11:07:47 +12:00
Luke D. Jones
3d41a7978a Fix crash when platform_profile not supported
Closes #130
2021-08-28 09:33:23 +12:00
Luke D. Jones
43fc467d58 Fix rm of not installed components 2021-08-28 00:25:51 +12:00
Luke D. Jones
6aba60f604 Try to re-get AniMe dev handle on write error 2021-08-27 22:31:50 +12:00
Luke D. Jones
a13dedf500 Cleanup 2021-08-27 20:46:04 +12:00
dragonn
cb490f23e9 Requesting dbus name after finishing initalizaction 2021-08-27 20:45:37 +12:00
Luke Jones
7dc8a743b9 Merge branch 'fluke/platform_curves' into 'main'
platform_profile + fan curve support

Closes #129 and #128

See merge request asus-linux/asusctl!75
2021-08-27 08:27:10 +00:00
Luke D. Jones
52f3b5a7bf Charge limit: try to support BAT<n>
Closes #128
2021-08-27 20:22:15 +12:00
Luke D. Jones
e89e7ca10f Add LED brightness pre/next cycle
Closes #129
2021-08-27 20:15:15 +12:00
Luke D. Jones
2431dd9e93 Remove supergfxctl to own repo 2021-08-26 16:06:57 +12:00
Luke D. Jones
453d3091c1 Bump major versions 2021-08-26 14:23:28 +12:00
Luke D. Jones
8db37491f3 Mention breaking changes in log 2021-08-26 13:57:19 +12:00
Luke D. Jones
cf915b9e00 Move anime data. Twiddle supergfxctl 2021-08-26 13:53:54 +12:00
Luke D. Jones
326ca37847 rog-supported crate 2021-08-26 13:17:17 +12:00
Luke D. Jones
498e604531 Major update to supergfx and others 2021-08-26 11:44:11 +12:00
Luke D. Jones
60b7f3be69 Begin cleanup 2021-08-25 11:42:32 +12:00
Luke D. Jones
6ceb5cf939 Major restructure to move gfx control out to crate 2021-08-25 11:16:23 +12:00
Luke D. Jones
0ed97db4c1 Temporary checkpoint 2021-08-24 12:35:57 +12:00
Luke D. Jones
8fcd05c2bb Append small extra help to bios option cli 2021-08-12 10:35:37 +12:00
Luke D. Jones
6de4590f27 Update fan curve to use git repo 2021-08-12 10:21:09 +12:00
Luke Jones
b097fd4da9 Merge branch 'fluke/anime' into 'main'
AniMe: more png colour type support

Closes #122 and #121

See merge request asus-linux/asusctl!73
2021-08-11 08:31:33 +00:00
Luke D. Jones
2a8e05707d AniMe: more png colour type support
Closes #121, #122
2021-08-11 20:27:44 +12:00
Luke Jones
a54e112978 Merge branch 'no_star_for_you' into 'main'
Remove Star from G513IH supported modes

See merge request asus-linux/asusctl!72
2021-08-04 01:04:57 +00:00
pshem
5785eb981d Remove Star from G513IH supported modes 2021-08-02 10:06:48 +01:00
Luke Jones
49234af08b Merge branch 'fluke/profiles' into 'main'
Fluke/profiles

See merge request asus-linux/asusctl!71
2021-08-01 22:53:38 +00:00
Luke D. Jones
8f5717def8 Version bump, various fixes 2021-08-02 10:50:17 +12:00
Luke D. Jones
9e55c0b2ca Fix incorrect name match of Star keyboard effect 2021-08-02 10:28:50 +12:00
Luke Jones
dd6ee91364 Merge branch 'main' into 'main'
Enable multizone support on Strix 513IH

See merge request asus-linux/asusctl!69
2021-08-01 22:03:30 +00:00
Luke Jones
efbb838ca1 Merge branch 'G513QY-ledmodes' into 'main'
add G513QY ledmodes

See merge request asus-linux/asusctl!70
2021-08-01 21:27:59 +00:00
Sonny Piers
daf7d39d41 add G513QY ledmodes 2021-08-01 23:12:59 +02:00
pshem
28b1194924 Fix multizone support on Strix 513IH 2021-08-01 18:00:04 +01:00
Luke Jones
73d95ca187 Merge branch 'fluke/profiles' into 'main'
fix: Profile select by name is correctly choosing

Closes #96 and #100

See merge request asus-linux/asusctl!68
2021-07-31 12:19:28 +00:00
Luke D. Jones
00b7c6482f fix: remove the parsing for root supported functions 2021-08-01 00:15:38 +12:00
Luke D. Jones
29c26e8c89 fix: Profile select by name is correctly choosing
Closes #100 #96
2021-08-01 00:10:11 +12:00
Luke D. Jones
fb124dd228 Fix clippy warnings 2021-07-31 23:09:23 +12:00
Luke D. Jones
0599be02dc fix: remove dbg!() output 2021-07-31 23:03:17 +12:00
Luke Jones
81a88263a9 Merge branch 'fluke/cli-fixes' into 'main'
Fluke/cli fixes

See merge request asus-linux/asusctl!67
2021-07-31 11:00:43 +00:00
Luke D. Jones
cea1fd2540 Fix small issues with CLI 2021-07-31 22:57:17 +12:00
Luke Jones
f2ced3bc7c Merge branch 'main' into 'main'
Add Zephyrus M GM501GS

Closes #109

See merge request asus-linux/asusctl!66
2021-07-30 23:48:58 +00:00
pshem
dc2a05894b Add Zephyrus M GM501GS 2021-07-30 17:45:00 +01:00
Luke D. Jones
9ee962ad09 systemd: sleep 2 after unit init 2021-07-30 14:35:44 +12:00
Luke Jones
eb7ef0af4f Merge branch 'main' into 'main'
add a protection to not allow running asusd in terminal

Closes #104

See merge request asus-linux/asusctl!64
2021-07-30 00:12:17 +00:00
Luke Jones
dc51120c27 Merge branch 'main' into 'main'
Add G533QR and 513IH to ledmodes

See merge request asus-linux/asusctl!65
2021-07-30 00:11:05 +00:00
pshem
fc4c2c4346 Add support for 513IH led modes 2021-07-24 19:34:09 +01:00
pshem
3f6be037c1 Add G533QR to ledmodes 2021-07-24 14:39:11 +01:00
Luke Jones
0a80c97f02 Update README.md 2021-07-13 04:36:39 +00:00
dragonn
88abafc728 add a protection to not allow running asusd in terminal 2021-07-09 18:40:38 +02:00
Luke Jones
ac880a0363 Merge branch 'fluke/gfx-mode-changes' into 'main'
Fluke/gfx mode changes

See merge request asus-linux/asusctl!63
2021-06-10 21:06:56 +00:00
Luke D. Jones
baebd51d99 Better control of gfx modes 2021-06-11 09:03:50 +12:00
Luke D. Jones
226620eb53 Fix up modes and icons 2021-06-07 19:19:49 +12:00
Luke D. Jones
1b34079d14 Trial of blocking vfio/compute unless in integrated mode 2021-06-07 11:02:21 +12:00
Luke D. Jones
8deeffcdad Minor fix to compute/vfio switch 2021-06-06 21:33:31 +12:00
Luke D. Jones
b7e45d7305 Bump versions for release 2021-06-06 21:02:07 +12:00
Luke D. Jones
d9077db234 Bugfix configs 2021-06-06 20:58:19 +12:00
Luke D. Jones
439b006342 Force change to integrated if in nvidia or hybrid mode
Force change to integrated if in nvidia or hybrid mode and user tries
to switch to vfio or compute
2021-06-06 13:44:34 +12:00
Luke D. Jones
ffa74d52e5 Fix LED brightness apply on resume 2021-06-06 12:12:17 +12:00
Luke Jones
6ccdd703e6 Merge branch 'fluke/anime-fade' into 'main'
Fluke/anime fade

See merge request asus-linux/asusctl!62
2021-05-31 01:07:17 +00:00
Luke D. Jones
bb910344b8 Basic fade in/out of gifs 2021-05-31 10:06:35 +12:00
Luke D. Jones
b9c4ff9ca7 Add GA503Q led modes 2021-05-30 10:20:17 +12:00
Luke D. Jones
62a18d4e57 Minor cleanup of bios controller 2021-05-29 15:33:47 +12:00
Luke D. Jones
f520e381a9 Attempt to provide more info to users gfx switching 2021-05-29 11:42:15 +12:00
Luke D. Jones
1dd543ddf3 Simplify the notifier 2021-05-27 13:22:08 +12:00
Luke Jones
a7ef63bd8a Merge branch 'formatted_supported_functions_message' into 'main'
Improving message formatting of supported functions

See merge request asus-linux/asusctl!61
2021-05-26 19:44:47 +00:00
KoStard
db43c0f2a4 Improving message formatting of supported functions
- Implementing fmt::Display for SupportedFunctions and sub-structs
2021-05-26 20:09:44 +04:00
Luke D. Jones
f0e5bb4ad1 dbus: send/recv notifications for bios options 2021-05-26 21:17:45 +12:00
Luke D. Jones
36bba75c50 bugfix: fix profile fan modes and creating 2021-05-26 09:24:18 +12:00
Luke Jones
b2dc610c0b Merge branch 'fluke/extras' into 'main'
bugfix: fix profile cycling

See merge request asus-linux/asusctl!60
2021-05-25 09:46:26 +00:00
Luke D. Jones
42d0eb0aba bugfix: fix profile cycling 2021-05-25 21:44:01 +12:00
Luke Jones
c14768182c Merge branch 'fluke/extras' into 'main'
Update config & dbus parts, cleanup deps, device power states

See merge request asus-linux/asusctl!59
2021-05-24 10:13:46 +00:00
Luke D. Jones
ef7e2135bf Prep for release 2021-05-24 22:10:30 +12:00
Luke D. Jones
2b58e259de Update config & dbus parts, cleanup deps, device power states
- Add extra config options and dbus methods
- Add power state signals for anime and led
- Refactor to use channels for dbus signal handler send/recv
- Split out profiles independant parts to a rog-profiles crate
- Cleanup dependencies
- Fix some dbus Supported issues
2021-05-24 18:56:21 +12:00
Luke D. Jones
ba03e8feb8 gfx: tmp informational only store of vfio/compute mode 2021-05-18 09:54:26 +12:00
Luke D. Jones
7771c6b8da gfx: Remove option for vfio/compute save 2021-05-18 09:18:36 +12:00
Luke D. Jones
04c9285ee6 add GX550L led modes 2021-05-17 12:25:16 +12:00
Luke D. Jones
bf4141e4b8 Additional info in manual 2021-05-16 15:59:39 +12:00
Luke D. Jones
233315f668 Small fix to heading in manual 2021-05-16 15:24:30 +12:00
Luke D. Jones
8332fb12f1 Update documents 2021-05-16 15:17:46 +12:00
Luke D. Jones
594e69f9b7 Minor readme update 2021-05-15 22:58:42 +12:00
Luke Jones
0aac0ce495 Merge branch 'fluke/refactor-patterns' into 'main'
bugfix: don't deadlock on change compute/vfio/compute

Closes #88 and #86

See merge request asus-linux/asusctl!58
2021-05-15 10:25:03 +00:00
Luke D. Jones
e24b4858a4 bugfix: don't deadlock on change compute/vfio/compute
Closes: #86 #88
2021-05-15 22:22:36 +12:00
Luke D. Jones
cf2b459e48 Add legal statement for trademarks 2021-05-06 12:29:12 +12:00
Luke D. Jones
895179fdad Add legal statement for trademarks 2021-05-06 12:27:59 +12:00
Luke Jones
fe3e8792eb Merge branch 'readmefix' into 'main'
corrected auto-builds url

See merge request asus-linux/asusctl!56
2021-05-03 18:53:15 +00:00
Aaron Johnson
1916641e2e corrected auto-builds url 2021-05-03 12:58:33 -05:00
Luke Jones
3ea0737be9 Merge branch 'fluke/refactor-patterns' into 'main'
Fluke/refactor patterns

See merge request asus-linux/asusctl!55
2021-04-26 03:53:21 +00:00
Luke D. Jones
c67373a830 bugfix: add version to user daemon. Fix multiple anime config 2021-04-26 15:49:35 +12:00
Luke D. Jones
41cbf4d353 Refactor dameon gfx 2021-04-25 22:53:38 +12:00
Luke Jones
7a4c14f7b8 Merge branch 'fluke/aura-crate' into 'main'
Release prep

See merge request asus-linux/asusctl!54
2021-04-25 03:07:13 +00:00
Luke D. Jones
f52a4d464a Release prep 2021-04-25 14:52:26 +12:00
Luke Jones
aa71592a31 Merge branch 'fluke/aura-crate' into 'main'
profiles: add dbus methods to change active profile

Closes #68, #73, and #81

See merge request asus-linux/asusctl!53
2021-04-25 02:37:31 +00:00
Luke D. Jones
dc6e8f8dcb profiles: add dbus methods to change active profile
Closes #81, #73, #68
2021-04-25 14:33:41 +12:00
Luke D. Jones
1a4836246f aura: support keyboard LED enable/disable with awake/sleep 2021-04-25 12:28:09 +12:00
Luke D. Jones
ab80b0742f gfx: asusd config option to not save compute/vfio mode switch 2021-04-20 21:10:23 +12:00
Luke D. Jones
6926aeed20 gfx: enable correct rebootless compute mode switch 2021-04-20 19:33:55 +12:00
Luke D Jones
f95e42e4b9 Reload LED mode on boot 2021-04-19 10:05:37 +12:00
Luke D Jones
82bee6b86e Update asusd unit for selinux 2021-04-15 19:43:09 +12:00
Luke D Jones
bd9bc8bcff anime: services for system sequences 2021-04-14 23:14:57 +12:00
Luke D Jones
8a6d364304 anime: initial system config work 2021-04-12 17:35:04 +12:00
Luke D Jones
64d99a3e05 gfx: partial save and recover of mode change
Properly set and recover to last mode for g-sync laptops

Partial close of #75
2021-04-12 10:49:08 +12:00
Luke D Jones
59f54b76f6 aura: split out all aura related files to rog-aura crate 2021-04-12 10:31:36 +12:00
Luke D Jones
6f36d91281 Begin rog-aura crate 2021-04-12 10:31:36 +12:00
Luke D Jones
e9f1fa01fc index on anime-cli: 0657c6c anime: prep rog-anime for publish, rename *all* AniMe~ to Anime 2021-04-12 10:31:36 +12:00
Luke D Jones
0d3a5d266b Changelog 2021-04-12 10:31:07 +12:00
Luke D Jones
cc28cee8bd anime: fix init 2021-04-11 22:47:21 +12:00
Luke D Jones
6ebf0c2bb2 Update makefile 2021-04-11 20:39:15 +12:00
Luke D Jones
77c658c94e Release 3.4.0 2021-04-11 20:36:31 +12:00
Luke Jones
df64a51372 Merge branch 'fluke/anime-cli' into 'main'
anime: prep rog-anime for publish, rename *all* AniMe~ to Anime

See merge request asus-linux/asusctl!50
2021-04-11 06:54:05 +00:00
Luke D Jones
0657c6cc74 anime: prep rog-anime for publish, rename *all* AniMe~ to Anime 2021-04-11 16:26:52 +12:00
Luke Jones
f116905e85 Merge branch 'fluke/anime-cli' into 'main'
anime: add zbus methods

See merge request asus-linux/asus-nb-ctrl!49
2021-04-10 09:58:56 +00:00
Luke D Jones
e515741efa anime: add zbus methods 2021-04-10 21:54:08 +12:00
Luke Jones
d516abdc92 Merge branch 'fluke/anime-cli' into 'main'
anime: tweak gif animation time types

See merge request asus-linux/asus-nb-ctrl!48
2021-04-09 11:21:35 +00:00
Luke D Jones
ece565de1c anime: tweak gif animation time types 2021-04-09 23:17:50 +12:00
Luke Jones
eb83d1a835 Merge branch 'fluke/anime-cli' into 'main'
anime: CLI and user-daemon work

See merge request asus-linux/asus-nb-ctrl!47
2021-04-09 08:45:06 +00:00
Luke D Jones
7d0f15d738 anime: CLI and user-daemon work 2021-04-09 20:41:25 +12:00
Luke Jones
8010da0891 Merge branch 'fluke/anime-cli' into 'main'
Fluke/anime cli

See merge request asus-linux/asus-nb-ctrl!46
2021-04-07 07:28:35 +00:00
Luke D Jones
aa500c35c4 daemon: revert zbus to 1.9.1 in daemon 2021-04-07 15:05:55 +12:00
Luke D Jones
2af33a0416 daemon: revert zbus to 1.9.1 in daemon 2021-04-07 15:05:26 +12:00
Luke D Jones
9b4ed6eb62 anime: discard frames if specified 2021-04-06 22:03:06 +12:00
Luke D Jones
47c1ca9fe4 anime: gif-image 2021-04-06 21:43:57 +12:00
Luke Jones
3cd624daf0 Merge branch 'fluke/anime-cli' into 'main'
Anime: Tweak the diagonal data to be more correct

See merge request asus-linux/asus-nb-ctrl!45
2021-04-06 02:01:41 +00:00
Luke D Jones
fa16864a3e Tweak the diagonal to be more correct 2021-04-06 13:56:02 +12:00
Luke Jones
bfc31b06d5 Merge branch 'fluke/anime-diag' into 'main'
Fluke/anime diag

See merge request asus-linux/asus-nb-ctrl!44
2021-04-05 09:12:04 +00:00
Luke D Jones
d854f7da1b Prepare for user saving of anime sequences 2021-04-05 21:06:53 +12:00
Luke D Jones
6d746b21a5 Anime gifs 2021-04-05 17:12:00 +12:00
Luke D Jones
226c083a51 Diagonal data structure 2021-04-05 00:02:05 +12:00
Luke Jones
de59d00949 Merge branch 'fluke/gfx-zbus-cleanup' into 'main'
Fluke/gfx zbus cleanup (incorrectly named branch)

Closes #72

See merge request asus-linux/asus-nb-ctrl!42
2021-04-03 08:46:17 +00:00
Luke D Jones
7ff01f12e9 Add extra models to ledmodes
- Configurable anime example
- Gfx power states as enum

Closes #72
2021-04-03 21:42:39 +13:00
Luke Jones
fbc248177a Merge branch 'fluke/gfx-vfio-optional' into 'main'
Put vfio behind config option

See merge request asus-linux/asus-nb-ctrl!43
2021-04-02 23:54:36 +00:00
Luke D Jones
fc3d7653f5 Add missing if condition for vfio 2021-04-03 12:50:13 +13:00
Luke D Jones
2dc70ea6af Put vfio behind config option 2021-04-03 09:59:36 +13:00
Luke D Jones
01345b28a5 Add extra models to ledmodes 2021-03-29 19:36:30 +13:00
322 changed files with 40780 additions and 7825 deletions

18
.cargo-husky/hooks/pre-commit Executable file
View File

@@ -0,0 +1,18 @@
#!/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
echo '+cargo cranky'
cargo cranky

10
.cargo-husky/hooks/pre-push Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
set -e
echo '+cargo +nightly fmt --all -- --check'
cargo +nightly fmt --all -- --check
echo '+cargo clippy --all -- -D warnings'
cargo clippy --all -- -D warnings
echo '+cargo cranky'
cargo cranky

23
.editorconfig Normal file
View File

@@ -0,0 +1,23 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[*.rs]
indent_size = 4
[tests/**/*.rs]
charset = utf-8
end_of_line = unset
indent_size = unset
indent_style = unset
trim_trailing_whitespace = unset
insert_final_newline = unset

21
.gitignore vendored
View File

@@ -1,2 +1,21 @@
/target
vendor.tar.xz
vendor.tar.xz
cargo-config
.idea
vendor
vendor-*
vendor_*
.vscode-ctags
.vscode
.~lock.*
*.ods#
# gnome extension
node-modules
bindings/ts/*.d.ts
bindings/ts/*.js.map
desktop-extensions/gnome*/dist
desktop-extensions/gnome*/@types/gir-generated
desktop-extensions/gnome*/node_modules
desktop-extensions/gnome*/schemas/gschemas.compiled
desktop-extensions/gnome*/*.zip

View File

@@ -1,26 +1,85 @@
image: rustdocker/rust:stable
image: rust:latest
.rust_cache: &rust_cache
cache:
# key: $CI_COMMIT_REF_SLUG
paths:
# Don't include `incremental` to save space
# Debug
- target/debug/build/
- target/debug/deps/
- target/debug/.fingerprint/
- target/debug/.cargo-lock
# Release
- target/release/build/
- target/release/deps/
- target/release/.fingerprint/
- target/release/.cargo-lock
before_script:
- apt-get update -qq && apt-get install -y -qq libdbus-1-dev libclang-dev libudev-dev
- apt-get update -qq && apt-get install -y -qq libinput-dev libseat-dev libudev-dev libgtk-3-dev grep llvm clang libclang-dev libsdl2-dev libsdl2-gfx-dev
stages:
- test
- build
- format
- check
- test
- release
- deploy
format:
except:
- tags
<<: *rust_cache
script:
- echo "nightly" > rust-toolchain
- rustup component add rustfmt
- cargo fmt --check
check:
except:
- tags
<<: *rust_cache
script:
- rustup component add clippy
- cargo check
# deny currently catches too much
#- cargo install cargo-deny && cargo deny
- cargo install cargo-cranky && cargo cranky
test:
except:
- tags
<<: *rust_cache
script:
- cargo check #+nightly check --features "clippy"
- mkdir -p .git/hooks > /dev/null
- cargo test --all
build:
release:
only:
- main
- tags
<<: *rust_cache
script:
- cargo install cargo-vendor-filterer
- make && make vendor
artifacts:
paths:
- vendor_asus-nb-ctrl_*.tar.xz
- cargo-config
- vendor_asusctl*.tar.xz
- cargo-config
pages:
stage: deploy
only:
- tags
<<: *rust_cache
script:
- cargo doc --document-private-items --no-deps --workspace
- rm -rf public
- mkdir public
- cp -R target/doc/* public
- cp extra/index.html public
artifacts:
paths:
- public
variables:
GIT_SUBMODULE_STRATEGY: normal

View File

@@ -0,0 +1,32 @@
## Issue description
(** I can not support distros which are outdated by default. This includes Ubuntu at least 50% of the time, and definitely includes Mint. **)
(Summarize the bug encountered)
## Steps to reproduce
(How can the issue be reproduced)
## What is the current bug behavior?
(What actually happens)
## What is the expected correct behavior?
(What you should see instead)
## Relevant logs and/or screenshots
(run `journalctl -b -u asusd > ~/asusd.log` and attach `~/asusd.log`)
(Paste any relevant logs - use code blocks (```) to format console output, logs, and code, as
it's very hard to read otherwise.)
## System details
- Distro:
- Kernel: (`uname -r`)
- Desktop:
- Xorg or wayland: ??
/label ~bug ~reproducable ~needs-investigation

File diff suppressed because it is too large Load Diff

5281
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,102 @@
[workspace.package]
version = "6.0.5"
rust-version = "1.77"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asusctl"
homepage = "https://gitlab.com/asus-linux/asusctl"
description = "Laptop feature control for ASUS ROG laptops and others"
edition = "2021"
[workspace]
members = ["asusctl", "asus-notify", "daemon", "rog-types", "rog-dbus"]
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",
]
default-members = [
"asusctl",
"asusd",
"asusd-user",
"cpuctl",
"rog-control-center",
]
resolver = "2"
[workspace.dependencies]
tokio = { version = "^1.36.0", default-features = false, features = [
"macros",
"sync",
"time",
"rt-multi-thread",
] }
concat-idents = "^1.1"
dirs = "^4.0"
smol = "^1.3"
mio = "0.8.11"
zbus = "4.1"
logind-zbus = { version = "4.0.2" } #, default-features = false, features = ["non_blocking"] }
serde = "^1.0"
serde_derive = "^1.0"
ron = "*"
typeshare = "1.0.0"
log = "^0.4"
env_logger = "^0.10.0"
glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8"
udev = { version = "^0.8", features = ["mio"] }
rusb = "^0.9"
inotify = "^0.10.0"
png_pong = "^0.8"
pix = "^0.13"
tinybmp = "^0.4.0"
gif = "^0.12.0"
versions = "6.2"
notify-rust = { git = "https://github.com/flukejones/notify-rust.git", rev = "54176413b81189a3e4edbdc20a0b4f7e2e35c063", default-features = false, features = [
"z",
] }
[profile.release]
lto = true
# thin = 57s, asusd = 9.0M
# fat = 72s, asusd = 6.4M
lto = "fat"
debug = false
opt-level = 3
panic = "abort"
codegen-units = 1
[profile.dev]
debug = false
opt-level = 1
codegen-units = 16
[profile.dev.package."*"]
opt-level = 1
codegen-units = 16
[profile.bench]
debug = false
opt-level = 3
[workspace.dependencies.cargo-husky]
version = "1"
default-features = false
features = ["user-hooks"]

121
Cranky.toml Normal file
View File

@@ -0,0 +1,121 @@
# https://github.com/ericseppanen/cargo-cranky
# cargo install cargo-cranky && cargo cranky
error = [
"clippy::all",
"clippy::await_holding_lock",
"clippy::bool_to_int_with_if",
"clippy::char_lit_as_u8",
"clippy::checked_conversions",
"clippy::dbg_macro",
"clippy::debug_assert_with_mut_call",
"clippy::disallowed_methods",
"clippy::disallowed_script_idents",
"clippy::doc_link_with_quotes",
"clippy::doc_markdown",
"clippy::empty_enum",
"clippy::enum_glob_use",
"clippy::equatable_if_let",
"clippy::exit",
"clippy::expl_impl_clone_on_copy",
"clippy::explicit_deref_methods",
"clippy::explicit_into_iter_loop",
"clippy::explicit_iter_loop",
"clippy::fallible_impl_from",
"clippy::filter_map_next",
"clippy::flat_map_option",
"clippy::float_cmp_const",
"clippy::fn_params_excessive_bools",
"clippy::fn_to_numeric_cast_any",
"clippy::from_iter_instead_of_collect",
"clippy::if_let_mutex",
"clippy::implicit_clone",
"clippy::imprecise_flops",
"clippy::index_refutable_slice",
"clippy::inefficient_to_string",
"clippy::invalid_upcast_comparisons",
"clippy::iter_not_returning_iterator",
"clippy::iter_on_empty_collections",
"clippy::iter_on_single_items",
"clippy::large_digit_groups",
"clippy::large_stack_arrays",
"clippy::large_types_passed_by_value",
"clippy::let_unit_value",
"clippy::linkedlist",
"clippy::lossy_float_literal",
"clippy::macro_use_imports",
"clippy::manual_assert",
"clippy::manual_instant_elapsed",
"clippy::manual_ok_or",
"clippy::manual_string_new",
"clippy::map_err_ignore",
"clippy::map_flatten",
"clippy::map_unwrap_or",
"clippy::match_on_vec_items",
"clippy::match_same_arms",
"clippy::match_wild_err_arm",
"clippy::match_wildcard_for_single_variants",
"clippy::mem_forget",
"clippy::mismatched_target_os",
"clippy::mismatching_type_param_order",
"clippy::missing_enforced_import_renames",
# "clippy::missing_errors_doc",
"clippy::missing_safety_doc",
"clippy::mut_mut",
"clippy::mutex_integer",
"clippy::needless_borrow",
"clippy::needless_continue",
"clippy::needless_for_each",
"clippy::needless_pass_by_value",
"clippy::negative_feature_names",
"clippy::nonstandard_macro_braces",
"clippy::option_option",
"clippy::path_buf_push_overwrite",
"clippy::ptr_as_ptr",
"clippy::rc_mutex",
"clippy::ref_option_ref",
"clippy::rest_pat_in_fully_bound_structs",
"clippy::same_functions_in_if_condition",
"clippy::semicolon_if_nothing_returned",
"clippy::single_match_else",
"clippy::str_to_string",
"clippy::string_add_assign",
"clippy::string_add",
"clippy::string_lit_as_bytes",
"clippy::string_to_string",
"clippy::todo",
"clippy::trailing_empty_array",
"clippy::trait_duplication_in_bounds",
"clippy::unimplemented",
"clippy::unnecessary_wraps",
"clippy::unnested_or_patterns",
"clippy::unused_peekable",
"clippy::unused_rounding",
# "clippy::unused_self",
"clippy::useless_transmute",
"clippy::verbose_file_reads",
"clippy::zero_sized_map_values",
"elided_lifetimes_in_paths",
"future_incompatible",
"nonstandard_style",
"rust_2018_idioms",
"rust_2021_prelude_collisions",
"rustdoc::missing_crate_level_docs",
"semicolon_in_expressions_from_macros",
"trivial_numeric_casts",
"unused_extern_crates",
"unused_import_braces",
"unused_lifetimes",
]
allow = [
# TODO(emilk): enable more lints
"clippy::cloned_instead_of_copied",
"clippy::derive_partial_eq_without_eq",
"clippy::type_complexity",
"clippy::undocumented_unsafe_blocks",
"trivial_casts",
"unsafe_op_in_unsafe_fn", # `unsafe_op_in_unsafe_fn` may become the default in future Rust versions: https://github.com/rust-lang/rust/issues/71668
"unused_qualifications",
]

446
MANUAL.md Normal file
View File

@@ -0,0 +1,446 @@
# asusctrl manual
**NOTE:** this manual is in need of an update in some places. If you find issues please file issue reports.
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features.
## Programs Available
- `asusd`: The main system daemon. It is autostarted by a udev rule and systemd unit.
- `asusd-user`: The user level daemon. Currently will run an anime sequence, with RGB keyboard sequences soon.
- `asusctl`: The CLI for interacting with the system daemon
## `asusd`
`asusd` is the main system-level daemon which will control/load/save various settings in a safe way for the user, along with exposing a _safe_ dbus interface for these interactions. This section covers only the daemon plus the various configuration file options.
The functionality that `asusd` exposes is:
- anime control
- led keyboard control (aura)
- charge limiting
- bios/efivar control
- power profile switching
- fan curves (if supported, this is auto-detected)
each of these will be detailed in sections.
### AniMe control
Controller for the fancy AniMe matrix display on the lid of some machines. This controller is a work in progress.
#### Config options
If you have an AniMe device a few system-level config options are enabled for you in `/etc/asusd/anime.conf`;
1. `"system": [],`: currently unused, is intended to be a default continuous sequence in future versions
2. `"boot": [],`: a sequence that plays on system boot (when asusd is loaded)
3. `"wake": [],`: a sequence that plays when waking from suspend
4. `"shutdown": [],`: a sequence that plays when shutdown begins
5. `"brightness": <FLOAT>`: global brightness control, where `<FLOAT> is 0.0-1.0
Some default examples are provided but are minimal. The full range of configuration options will be covered in another section of this manual.
### Led keyboard control
The LED controller (e.g, aura) enables setting many of the factory modes available if a laptop supports them. It also enables per-key RGB settings but this is a WIP and will likely be similar to how AniMe sequences can be created.
#### 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).
### Charge control
Almost all modern ASUS laptops have charging limit control now. This can be controlled in `/etc/asusd/asusd.conf`.
```json
"bat_charge_limit": 80,
```
where the number is a percentage.
### Bios control
Some options that you find in Armory Crate are available under this controller, so far there is:
- POST sound: this is the sound you hear on bios boot post
- GPU MUX: this controls if the dGPU is the _only_ GPU, making it the main GPU and disabling the iGPU
These options are not written to the config file as they are stored in efivars. The only way to change these is to use the exposed safe dbus methods, or use the `asusctl` CLI tool.
### Profiles
asusctl can support setting a power profile via platform_profile drivers. This requires [power-profiles-daemon](https://gitlab.freedesktop.org/hadess/power-profiles-daemon) v0.10.0 minimum. It also requires the kernel patch for platform_profile support to be applied form [here](https://lkml.org/lkml/2021/8/18/1022) - this patch is merged to 5.15 kernel upstream.
A common use of asusctl is to bind the `fn+f5` (fan) key to `asusctl profile -n` to cycle through the 3 profiles:
1. Balanced
2. Performance
3. Quiet
#### Fan curves
Fan curve support requires a laptop that supports it (this is detected automatically) and the kernel patch from [here](https://lkml.org/lkml/2021/10/23/250) which is accepted for the 5.17 kernel release .
The fan curve format can be of varying formats:
- `30c:0%,40c:5%,50c:10%,60c:20%,70c:35%,80c:55%,90c:65%,100c:65%"`
- `30:0,40:5,50:10,60:20,70:35,80:55,90:65,100:65"`
- `30 0,40 5,50 10,60 20,70 35,80 55,90 65,100 65"`
- `30 0 40 5 50 10 60 20 70 35 80 55 90 65 100 65"`
the order must always be the same "temperature:percentage", lowest from left to rigth being highest.
The config file is located at `/etc/asusd/profile.conf` and is self-descriptive. On first run it is populated with the system EC defaults.
### Support controller
There is one more controller; the support controller. The sole pupose of this controller is to querie all the other controllers for information about their support level for the host laptop. Returns a json string.
## asusd-user
`asusd-user` is a usermode daemon. The intended purpose is to provide a method for users to run there own custom per-key keyboard effects and modes, AniMe sequences, and possibly their own profiles - all without overwriting the _base_ system config. As such some parts of the system daemon will migrate to the user daemon over time with the expectation that the Linux system runs both.
As of now only AniMe is active in this with configuration in `~/.config/rog/`. On first run defaults are created that are intended to work as examples.
The main config is `~/.config/rog/rog-user.cfg`
#### Config options: Aura, per-key and zoned
I'm unsure of how many laptops this works on, so please try it.
`led_type: Key` works only on actual per-key RGB keyboards.
`led_type: Zone` works on zoned laptops.
`led_type: Zone` set to `None` works on zoned ROG laptops, unzoned ROG laptops, and TUF laptops (and yes this does mean an audio EQ can be done now).
`~/.config/rog/rog-user.cfg` contains a setting `"active_aura": "<FILENAME>"` where `<FILENAME>` is the name of the Aura config to use, located in the same directory and without the file postfix, e.g, `"active_anime": "aura-default"`
An Aura config itself is a file with contents:
```ron
(
name: "aura-default",
aura: (
effects: [
Breathe((
led: W,
start_colour1: (255, 0, 20),
start_colour2: (20, 255, 0),
speed: Low,
)),
Breathe((
led: A,
start_colour1: (255, 0, 20),
start_colour2: (20, 255, 0),
speed: Low,
)),
Breathe((
led: S,
start_colour1: (255, 0, 20),
start_colour2: (20, 255, 0),
speed: Low,
)),
Breathe((
led: D,
start_colour1: (255, 0, 20),
start_colour2: (20, 255, 0),
speed: Low,
)),
Breathe((
led: F,
start_colour1: (255, 0, 0),
start_colour2: (255, 0, 0),
speed: High,
)),
Static((
led: RCtrl,
colour: (0, 0, 255),
)),
Static((
led: LCtrl,
colour: (0, 0, 255),
)),
Static((
led: Esc,
colour: (0, 0, 255),
)),
DoomFlicker((
led: N9,
start_colour: (0, 0, 255),
max_percentage: 80,
min_percentage: 40,
)),
],
zoned: false,
),
)
```
If your laptop supports multizone, `"led"` can also be `"Zone": <one of the following>`
- `SingleZone` // Keyboards with only one zone
- `ZonedKbLeft` // keyboard left
- `ZonedKbLeftMid` // keyboard left-middle
- `ZonedKbRightMid` // etc
- `ZonedKbRight`
- `LightbarRight`
- `LightbarRightCorner`
- `LightbarRightBottom`
- `LightbarLeftBottom`
- `LightbarLeftCorner`
- `LightbarLeft`
Single zone example:
```ron
(
name: "aura-default",
aura: (
effects: [
DoomFlicker((
led: SingleZone,
start_colour: (200, 40, 5),
max_percentage: 80,
min_percentage: 40,
)),
],
zoned: true,
),
)
```
At the moment there are only three effects available as shown in the example. More will come in the future
but this may take me some time.
#### Config options: AniMe
`~/.config/rog/rog-user.cfg` contains a setting `"active_anime": "<FILENAME>"` where `<FILENAME>` is the name of the AniMe config to use, located in the same directory and without the file postfix, e.g, `"active_anime": "anime-doom"`
An AniMe config itself is a file with contents:
```json
{
"name": "<FILENAME>",
"anime": []
}
```
`<FILENAME>` is used as a reference internally. `"anime": []` is an array of sequences (WIP).
##### "anime" array options
Each object in the array can be one of:
1. AsusAnimation
2. ImageAnimation
3. Image
4. Pause
##### AsusAnimation
`AsusAnimation` is specifically for running the gif files that Armory Crate comes with. `asusctl` includes all of these in `/usr/share/asusd/anime/asus/`
```json
"AsusAnimation": {
"file": "<FILE_PATH>",
"time": <TIME>,
"brightness": <FLOAT>
}
```
##### AsusImage
Virtually the same as `AsusAnimation` but for png files, typically created in the same "slanted" style using a template (`diagonal-template.png`) as the ASUS gifs for pixel perfection.
```json
"AsusImage": {
"file": "<FILE_PATH>",
"time": <TIME>,
"brightness": <FLOAT>
}
```
##### ImageAnimation
`ImageAnimation` can play _any_ gif of any size.
```json
"ImageAnimation": {
"file": "<FILE_PATH>",
"scale": <FLOAT>,
"angle": <FLOAT>,
"translation": [
<FLOAT>,
<FLOAT>
],
"time": <TIME>,
"brightness": <FLOAT>
}
},
```
##### Image
`Image` currently requires 8bit greyscale png. It will be able to use most in future.
```json
{
"Image": {
"file": "<FILE_PATH>",
"scale": <FLOAT>,
"angle": <FLOAT>,
"translation": [
<FLOAT>,
<FLOAT>
],
"time": <TIME>,
"brightness": <FLOAT>
}
},
```
##### Pause
A `Pause` is handy for after an `Image` to hold the `Image` on the AniMe for a period.
```json
{
"Pause": {
"secs": <INT>,
"nanos": <INT>
}
},
```
##### Options for objects
**<FILE_PATH>**
Must be full path: `"/usr/share/asusd/anime/asus/gaming/Controller.gif"` or `/home/luke/Downloads/random.gif`.
**<FLOAT>**
A number from 0.0-1.0.
- `brightness`: If it is brightness it is combined with the system daemon global brightness
- `scale`: 1.0 is the original size with lower number shrinking, larger growing
- `angle`: Rotation angle in radians
- `translation`: Shift the image X -/+, and y -/+
**<TIME>**
Time is the length of time to run the gif for:
```json
"time": {
"Time": {
"secs": 5,
"nanos": 0
}
},
```
A cycle is how many gif loops to run:
```json
"time": {
"Cycles": 2
},
```
`Infinite` means that this gif will never end:
```json
"time": "Infinite",
```
`Fade` allows an image or gif to fade in and out, and remain at max brightness to n time:
```json
"time": {
"Fade": {
"fade_in": {
"secs": 2,
"nanos": 0
},
"show_for": {
"secs": 1,
"nanos": 0
},
"fade_out": {
"secs": 2,
"nanos": 0
}
}
},
```
`show_for` can be `null`, if it is `null` then the `show_for` becomes `gif_time_length - fade_in - fade_out`.
This is period for which the gif or image will be max brightness (as set).
**<INT>**
A plain non-float integer.
## asusctl
`asusctl` is a commandline interface which intends to be the main method of interacting with `asusd`. It can be used in any place a terminal app can be used.
This program will query `asusd` for the `Support` level of the laptop and show or hide options according to this support level.
Most commands are self-explanatory.
### CLI Usage and help
Commands are given by:
```
asusctl <option> <command> <command-options>
```
Help is available through:
```
asusctl --help
asusctl <command> --help
```
Some commands may have subcommands:
```
asusctl <command> <subcommand> --help
```
### Keybinds
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next**
```
asusctl led-mode -n
```
**Previous**
```
asusctl led-mode -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
# License & Trademarks
Mozilla Public License 2 (MPL-2.0)
---
ASUS and ROG Trademark is either a US registered trademark or trademark of ASUSTeK Computer Inc. in the United States and/or other countries.
Reference to any ASUS products, services, processes, or other information and/or use of ASUS Trademarks does not constitute or imply endorsement, sponsorship, or recommendation thereof by ASUS.
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
---

View File

@@ -1,4 +1,4 @@
VERSION := $(shell grep -Pm1 'version = "(\d.\d.\d)"' daemon/Cargo.toml | cut -d'"' -f2)
VERSION := $(shell /usr/bin/grep -Pm1 'version = "(\d.\d.\d)"' Cargo.toml | cut -d'"' -f2)
INSTALL = install
INSTALL_PROGRAM = ${INSTALL} -D -m 0755
@@ -11,19 +11,23 @@ datarootdir = $(prefix)/share
libdir = $(exec_prefix)/lib
zshcpl = $(datarootdir)/zsh/site-functions
BIN_ROG := rog-control-center
BIN_C := asusctl
BIN_D := asusd
BIN_N := asus-notify
LEDCFG := asusd-ledmodes.toml
X11CFG := 90-nvidia-screen-G05.conf
PMRULES := 90-asusd-nvidia-pm.rules
BIN_U := asusd-user
LEDCFG := aura_support.ron
SRC := Cargo.toml Cargo.lock Makefile $(shell find -type f -wholename '**/src/*.rs')
STRIP_BINARIES ?= 0
DEBUG ?= 0
ifeq ($(DEBUG),0)
ARGS += --release
TARGET = release
else
ARGS += --profile dev
TARGET = debug
endif
VENDORED ?= 0
@@ -39,39 +43,65 @@ clean:
distclean:
rm -rf .cargo vendor vendor.tar.xz
install:
$(INSTALL_PROGRAM) "./target/release/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
$(INSTALL_PROGRAM) "./target/release/$(BIN_N)" "$(DESTDIR)$(bindir)/$(BIN_N)"
$(INSTALL_DATA) "./data/$(PMRULES)" "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
install-program:
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_ROG)" "$(DESTDIR)$(bindir)/$(BIN_ROG)"
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_C)" "$(DESTDIR)$(bindir)/$(BIN_C)"
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_D)" "$(DESTDIR)$(bindir)/$(BIN_D)"
$(INSTALL_PROGRAM) "./target/$(TARGET)/$(BIN_U)" "$(DESTDIR)$(bindir)/$(BIN_U)"
install-data:
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).desktop" "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop"
$(INSTALL_DATA) "./rog-control-center/data/$(BIN_ROG).png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/$(BIN_ROG).png"
cd rog-aura/data/layouts && find . -type f -name "*.ron" -exec $(INSTALL_DATA) "{}" "$(DESTDIR)$(datarootdir)/rog-gui/layouts/{}" \;
$(INSTALL_DATA) "./data/$(BIN_D).rules" "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
$(INSTALL_DATA) "./data/$(LEDCFG)" "$(DESTDIR)/etc/asusd/$(LEDCFG)"
$(INSTALL_DATA) "./rog-aura/data/$(LEDCFG)" "$(DESTDIR)$(datarootdir)/asusd/$(LEDCFG)"
$(INSTALL_DATA) "./data/$(BIN_D).conf" "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
$(INSTALL_DATA) "./data/$(X11CFG)" "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
$(INSTALL_DATA) "./data/$(BIN_D).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
$(INSTALL_DATA) "./data/$(BIN_N).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
$(INSTALL_DATA) "./data/$(BIN_U).service" "$(DESTDIR)$(libdir)/systemd/user/$(BIN_U).service"
$(INSTALL_DATA) "./data/icons/asus_notif_yellow.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
$(INSTALL_DATA) "./data/icons/asus_notif_green.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
$(INSTALL_DATA) "./data/icons/asus_notif_blue.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_blue.png"
$(INSTALL_DATA) "./data/icons/asus_notif_red.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
$(INSTALL_DATA) "./data/_asusctl" "$(DESTDIR)$(zshcpl)/_asusctl"
$(INSTALL_DATA) "./data/completions/asusctl.fish" "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
$(INSTALL_DATA) "./data/icons/asus_notif_orange.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_orange.png"
$(INSTALL_DATA) "./data/icons/asus_notif_white.png" "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_white.png"
$(INSTALL_DATA) "./data/icons/scalable/gpu-compute.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg"
$(INSTALL_DATA) "./data/icons/scalable/gpu-hybrid.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg"
$(INSTALL_DATA) "./data/icons/scalable/gpu-integrated.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-integrated.svg"
$(INSTALL_DATA) "./data/icons/scalable/gpu-nvidia.svg" "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg"
$(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: install-program install-data
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_ROG)"
rm -r "$(DESTDIR)$(datarootdir)/applications/$(BIN_ROG).desktop"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/$(BIN_ROG).png"
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_D)"
rm -f "$(DESTDIR)$(bindir)/$(BIN_N)"
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/$(PMRULES)"
rm -f "$(DESTDIR)$(libdir)/udev/rules.d/99-$(BIN_D).rules"
rm -f "$(DESTDIR)/etc/asusd/$(LEDCFG)"
rm -f "$(DESTDIR)$(datarootdir)/dbus-1/system.d/$(BIN_D).conf"
rm -f "$(DESTDIR)$(datarootdir)/X11/xorg.conf.d/$(X11CFG)"
rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN_D).service"
rm -r "$(DESTDIR)$(libdir)/systemd/user/$(BIN_N).service"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_yellow.png"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_green.png"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/512x512/apps/asus_notif_red.png"
rm -f "$(DESTDIR)$(zshcpl)/_asusctl"
rm -f "$(DESTDIR)$(datarootdir)/fish/vendor_completions.d/asusctl.fish"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-compute.svg"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-hybrid.svg"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-integrated.svg"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-nvidia.svg"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/gpu-vfio.svg"
rm -r "$(DESTDIR)$(datarootdir)/icons/hicolor/scalable/status/notification-reboot.svg"
rm -rf "$(DESTDIR)$(datarootdir)/asusd"
rm -rf "$(DESTDIR)$(datarootdir)/rog-gui"
update:
cargo update
@@ -82,14 +112,33 @@ vendor:
echo 'directory = "vendor"' >> .cargo/config
mv .cargo/config ./cargo-config
rm -rf .cargo
tar pcfJ vendor_asus-nb-ctrl_$(VERSION).tar.xz vendor
rm -rf vendor
cargo vendor-filterer --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
build:
ifeq ($(VENDORED),1)
cargo vendor
@echo "version = $(VERSION)"
tar pxf vendor_asus-nb-ctrl_$(VERSION).tar.xz
tar pxf vendor_asusctl_$(VERSION).tar.xz
endif
cargo build $(ARGS)
ifneq ($(STRIP_BINARIES),0)
strip -s ./target/$(TARGET)/$(BIN_C)
strip -s ./target/$(TARGET)/$(BIN_D)
strip -s ./target/$(TARGET)/$(BIN_U)
strip -s ./target/$(TARGET)/$(BIN_ROG)
endif
.PHONY: all clean distclean install uninstall update build
.PHONY: all clean distclean install uninstall update build bindings

255
README.md
View File

@@ -1,34 +1,39 @@
# ASUS NB Ctrl
# `asusctl` for ASUS ROG
[![](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate/?hosted_button_id=4V2DEPS7K6APC) - [Asus Linux Website](https://asus-linux.org/)
[Become a Patron!](https://www.patreon.com/bePatron?u=7602281) - [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.
`asusd` is a utility for Linux to control many aspects of various ASUS laptops
but can also be used with non-asus laptops with reduced features.
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 lat 2022 devices.
Z13 devices will need [these](https://lore.kernel.org/linux-input/20240416090402.31057-1-luke@ljones.dev/T/#t)
## Goals
1. To provide an interface for rootless control of some system functions most users wish to control such as fan speeds, keyboard LEDs, graphics modes.
2. Enable third-party apps to use the above with dbus methods
3. To make the above as easy as possible for new users
The main goal of this work is to provide a safe and easy to use abstraction over various laptop features via DBUS, and to provide some helpful defaults and other behaviour such as toggling throttle/profile on AC/battery change.
Point 3 means that the list of supported distros is very narrow - fedora is explicitly
supported, while Ubuntu and openSUSE are level-2 support. All other distros are *not*
supported (while asusd might still run fine on them). For best support use fedora 32+ Workstation.
1. Provide safe dbus interface
2. Respect the users resources: be small, light, and fast
**NOTICE:**
1. The following is *not* required for 5.11 kernel versions, as this version includes all the required patches.
2. 2021 hardware has a new keyboard prod_id and the patch is included in 5.12+
Point 4? asusd currently uses a tiny fraction of cpu time, and less than 1Mb of ram, the way
a system-level daemon should. Languages such as JS and python should never be used for system level daemons (please stop).
'hid-asus-rog` DKMS module from [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/).
## Keyboard LEDs
The module enables the following in kernel:
The level of support for laptops is dependent on folks submitting data to include in [`./rog-aura/data/layouts/aura_support.ron`](./rog-aura/data/layouts/aura_support.ron), typically installed in `/usr/share/asusd/aura_support.ron`. This is because the controller used for keyboards and LEDs is used across many years and many laptop models, all with different firmware configurations - the only way to track this is with the file mentioned above. Why not just enable all by default? Because it confuses people.
- Initialising the keyboard
- All hotkeys (FN+Key combos)
See the [rog-aura readme](./rog-aura/README.md) for more details.
## Discord
[Discord server link](https://discord.gg/ngbdKabAnP)
[![Discord](https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/z8y99XqPb7)
## SUPPORTED LAPTOPS
@@ -39,203 +44,111 @@ to this:
Bus 001 Device 002: ID 0b05:1866 ASUSTek Computer, Inc. N-KEY Device
```
or
```
Bus 003 Device 002: ID 0b05:19b6 ASUSTek Computer, Inc. [unknown]
```
then it may work without tweaks. Technically all other functions except the LED
and AniMe parts should work regardless of your latop make. Eventually this project
will probably suffer another rename once it becomes generic enough to do so.
and AniMe parts should work regardless of your latop make.
## Implemented
- [X] System daemon
- [X] User notifications daemon
- [X] Setting/modifying built-in LED modes
- [X] Per-key LED setting
- [X] Fancy LED modes (See examples) (currently being reworked)
- [X] Saving settings for reload
- [X] Logging - required for journalctl
- [X] AniMatrix display on G14 models that include it (currently being reworked)
- [X] Set battery charge limit (with kernel supporting this)
- [X] Fan curve control on G14 + G15 thanks to @Yarn1
- [X] Graphics mode switching between iGPU, dGPU, on-demand, and vfio (for VM pass-through)
+ [X] Requires only a logout/login
- [X] Toggle bios setting for boot/POST sound
- [X] Toggle bios setting for "dedicated gfx" mode on supported laptops (g-sync)
The list is a bit outdated as many features have been enabled in the Linux kernel with upstream patches and then supported in asusctl suite.
# FUNCTIONS
- [x] System daemon
- [x] GUI app (includes tray and notifications)
- [x] Setting/modifying built-in LED modes
- [x] Per-key LED setting
- [x] Fancy LED modes (See examples) (currently being reworked)
- [x] AniMatrix display on G14 and M16 models that include it
- [x] Set battery charge limit (with kernel supporting this)
- [x] Fan curve control on supported laptops (G14/G15, some TUF like FA507)
- [x] Toggle bios setting for boot/POST sound
- [x] Toggle GPU MUX (g-sync, or called MUX on 2022+ laptops)
## Graphics switching
# GUI
`asusd` can switch graphics modes between:
- `integrated`, uses the iGPU only and force-disables the dGPU
- `hybrid`, enables Nvidia prime-offload mode
- `nvidia`, uses the Nvidia gpu only
- `vfio`, binds the Nvidia gpu to vfio for VM pass-through
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.
This can be disabled in the config with `"manage_gfx": false,`. Additionally there
is an extra setting for laptops capable of g-sync dedicated gfx mode to enable the
graphics switching to switch on dedicated gfx for "nvidia" mode.
This switcher conflicts with other gpu switchers like optimus-manager, suse-prime
or ubuntu-prime, system76-power, and bbswitch. If you have issues with `asusd`
always defaulting to `integrated` mode on boot then you will need to check for
stray configs blocking nvidia modules from loading in:
- `/etc/modprobe.d/`
- `/usr/lib/modprope.d/`
**VFIO NOTE:** The vfio modules *must not* be compiled into the kernel, they need
to be separate modules. If you don't plan to use vfio mode then you can ignore this
otherwise you may need a custom built kernel.
### Power management udev rule
If you have installed the Nvidia driver manually you will require the
`data/90-asusd-nvidia-pm.rules` udev rule to be installed in `/etc/udev/rules.d/`.
### fedora and openSUSE
You *may* need a file `/etc/dracut.conf.d/90-nvidia-dracut-G05.conf` installed
to stop dracut including the nvidia modules in the ramdisk if you manually
installed the nvidia drivers.
```
# filename /etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
and run `dracut -f` after creating it.
## KEYBOARD BACKLIGHT MODES
Models GA401, GA502, GU502 support LED brightness change only (no RGB).
If you model isn't getting the correct led modes, you can edit the file
`/etc/asusd/asusd-ledmodes.toml`, the LED Mode numbers are as follows:
- Static
- Breathe
- Strobe
- Rainbow
- Star
- Rain
- Highlight
- Laser
- Ripple
- Pulse
- Comet
- Flash
use `cat /sys/class/dmi/id/product_name` to get details about your laptop. You
must restart the `asusd.service` after editing.
# Keybinds
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next**
```
asusctl led-mode -n
```
**Previous**
```
asusctl led-mode -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
**NOTE**: Xorg is not supported.
# BUILDING
Requirements are rust >= 1.40 installed from rustup.io if the distro provided version is too old, and `make`.
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.
**Ubuntu*:** `apt install libclang-dev libudev-dev`
**fedora:**
**fedora:** `dnf install clang-devel systemd-devel`
dnf install cmake clang-devel libinput-devel libseat-devel libgbm-devel libxkbcommon-devel systemd-devel libdrm-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 libinput-devel libseat-devel libgbm-devel libxkbcommon-devel systemd-devel libdrm-devel expat-devel pcre2-devel libzstd-devel gtk3-devel
make
sudo make install
**Ubuntu, Popos (unsuported):**
instructions removed as outdated
## Installing
Packaging and auto-builds are available [here](https://build.opensuse.org/package/show/home:luke_nukem:asus/asus-nb-ctrl)
- Fedora copr = https://copr.fedorainfracloud.org/coprs/lukenukem/asus-linux/
- openSUSE = https://download.opensuse.org/repositories/home:/luke_nukem:/asus/
Download repositories are available [here](https://download.opensuse.org/repositories/home:/luke_nukem:/asus/)
---
Run `make` then `sudo make install` then reboot.
=======
The default init method is to use the udev rule, this ensures that the service is
started when the device is initialised and ready.
You may also need to activate the service for debian install. If running Pop!\_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
## Upgrading
If you are upgrading from a previous installed version, you will need to restart the service or reboot.
```
$ systemctl daemon-reload && systemctl restart asusd
```
You may also need to activate the service for debian install. If running Pop!_OS, I suggest disabling `system76-power` gnome-shell extension and systemd service.
If you would like to run this daemon on another non-ASUS laptop you can. You'll
have all features available except the LED and AniMe control (further controllers
can be added on request). You will need to install the alternative service from
`data/asusd-alt.service`.
## Uninstalling
Run `sudo make uninstall` in the source repo, and remove `/etc/asusd/`.
# USAGE
# Contributing
Commands are given by:
See `CONTRIBUTING.md`. Additionally, also do `cargo clean` and `cargo test` on first checkout to ensure the commit hooks are used (via `cargo-husky`).
```
asusctl <option> <command> <command-options>
```
Generation of the bindings with `make bindings` requires `typeshare` to be installed.
Help is available through:
```
asusctl --help
asusctl <command> --help
```
Some commands may have subcommands:
```
asusctl <command> <subcommand> --help
```
## User NOTIFICATIONS via dbus
If you have a notifications handler set up, or are using KDE or Gnome then you
can enable the user service to get basic notifications when something changes.
```
systemctl --user enable asus-notify.service
systemctl --user start asus-notify.service
```
Dbus introsepction XML requires with `make introspection` requires `anime_sim` to be running before starting `asusd`.
# OTHER
## AniMe input
## AniMe Matrix simulator
You will want to look at what MeuMeu has done with [https://github.com/Meumeu/ZephyrusBling/](https://github.com/Meumeu/ZephyrusBling/)
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
Please file a support request.
## Notes:
- If charge limit or fan modes are not working, then you may require a kernel newer than 5.6.10.
- AniMe device check is performed on start, if your device has one it will be detected.
- GA14/GA401 and GA15/GA502/GU502, You will need kernel [patches](https://lab.retarded.farm/zappel/asus-rog-zephyrus-g14/-/tree/master/kernel_patches), these are on their way to the kernel upstream.
- On fedora manually installed Nvidia driver requires a dracut config as follows:
```
# filename/etc/dracut.conf.d/90-nvidia-dracut-G05.conf
# Omit the nvidia driver from the ramdisk, to avoid needing to regenerate
# the ramdisk on updates, and to ensure the power-management udev rules run
# on module load
omit_drivers+=" nvidia nvidia-drm nvidia-modeset nvidia-uvm "
```
# License
# License & Trademarks
Mozilla Public License 2 (MPL-2.0)
---
ASUS and ROG Trademark is either a US registered trademark or trademark of ASUSTeK Computer Inc. in the United States and/or other countries.
Reference to any ASUS products, services, processes, or other information and/or use of ASUS Trademarks does not constitute or imply endorsement, sponsorship, or recommendation thereof by ASUS.
The use of ROG and ASUS trademarks within this website and associated tools and libraries is only to provide a recognisable identifier to users to enable them to associate that these tools will work with ASUS ROG laptops.
---

View File

@@ -1,19 +0,0 @@
[package]
name = "asus-notify"
version = "3.0.0"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# serialisation
serde_json = "^1.0"
rog_dbus = { path = "../rog-dbus" }
rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
[dependencies.notify-rust]
version = "^4.0"
default-features = false
features = ["z"]

View File

@@ -1,113 +0,0 @@
use notify_rust::{Hint, Notification, NotificationHandle};
use rog_dbus::{DbusProxies, Signals};
use rog_types::profile::Profile;
use std::error::Error;
use std::time::Duration;
fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("asus-notify version {}", env!("CARGO_PKG_VERSION"));
println!(" daemon version {}", daemon::VERSION);
println!(" rog-dbus version {}", rog_dbus::VERSION);
// let mut cfg = Config::read_new()?;
// let mut last_profile = String::new();
let (proxies, conn) = DbusProxies::new()?;
let signals = Signals::new(&proxies)?;
let mut last_profile_notif: Option<NotificationHandle> = None;
let mut last_led_notif: Option<NotificationHandle> = None;
let mut last_gfx_notif: Option<NotificationHandle> = None;
let mut last_chrg_notif: Option<NotificationHandle> = None;
let recv = proxies.setup_recv(conn);
loop {
std::thread::sleep(Duration::from_millis(100));
recv.next_signal().unwrap();
if let Ok(mut lock) = signals.gfx_vendor.lock() {
if let Some(vendor) = lock.take() {
if let Some(notif) = last_gfx_notif.take() {
notif.close();
}
let x = do_notif(&format!(
"Graphics mode changed to {}",
<&str>::from(vendor)
))?;
last_gfx_notif = Some(x);
}
}
if let Ok(mut lock) = signals.charge.lock() {
if let Some(limit) = lock.take() {
if let Some(notif) = last_chrg_notif.take() {
notif.close();
}
let x = do_notif(&format!("Battery charge limit changed to {}", limit))?;
last_chrg_notif = Some(x);
}
}
if let Ok(mut lock) = signals.profile.lock() {
if let Some(profile) = lock.take() {
if let Some(notif) = last_profile_notif.take() {
notif.close();
}
if let Ok(profile) = serde_json::from_str(&profile) {
let profile: Profile = profile;
if let Ok(name) = proxies.profile().active_profile_name() {
let x = do_thermal_notif(&profile, &name)?;
last_profile_notif = Some(x);
}
}
}
}
if let Ok(mut lock) = signals.led_mode.lock() {
if let Some(ledmode) = lock.take() {
if let Some(notif) = last_led_notif.take() {
notif.close();
}
let x = do_notif(&format!(
"Keyboard LED mode changed to {}",
ledmode.mode_name()
))?;
last_led_notif = Some(x);
}
}
}
}
fn do_thermal_notif(profile: &Profile, label: &str) -> Result<NotificationHandle, Box<dyn Error>> {
let fan = profile.fan_preset;
let turbo = if profile.turbo { "enabled" } else { "disabled" };
let icon = match fan {
0 => "asus_notif_yellow",
1 => "asus_notif_red",
2 => "asus_notif_green",
_ => "asus_notif_red",
};
let x = Notification::new()
.summary("ASUS ROG")
.body(&format!(
"Thermal profile changed to {}, turbo {}",
label.to_uppercase(),
turbo
))
.hint(Hint::Resident(true))
.timeout(2000)
.hint(Hint::Category("device".into()))
//.hint(Hint::Transient(true))
.icon(icon)
.show()?;
Ok(x)
}
fn do_notif(body: &str) -> Result<NotificationHandle, Box<dyn Error>> {
let x = Notification::new()
.summary("ASUS ROG")
.body(body)
.timeout(2000)
.show()?;
Ok(x)
}

View File

@@ -1,21 +1,28 @@
[package]
name = "asusctl"
version = "3.1.5"
authors = ["Luke D Jones <luke@ljones.dev>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
license.workspace = true
version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies]
# serialisation
serde_json = "^1.0"
rog_anime = { path = "../rog-anime" }
rog_slash = { path = "../rog-slash" }
rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" }
rog_types = { path = "../rog-types" }
daemon = { path = "../daemon" }
gumdrop = "^0.8"
yansi-term = "^0.1"
rog_profiles = { path = "../rog-profiles" }
rog_platform = { path = "../rog-platform" }
asusd = { path = "../asusd" }
dmi_id = { path = "../dmi-id" }
ron.workspace = true
gumdrop.workspace = true
zbus.workspace = true
[dev-dependencies]
tinybmp = "^0.2.3"
rog_dbus = { path = "../rog-dbus" }
rog_dbus = { path = "../rog-dbus" }
cargo-husky.workspace = true

View File

@@ -1,42 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::anime_matrix::{AniMeImageBuffer, AniMePacketType, HEIGHT, WIDTH};
use tinybmp::{Bmp, Pixel};
fn main() {
let (client, _) = AuraDbusClient::new().unwrap();
let bmp =
Bmp::from_slice(include_bytes!("non-skewed_r.bmp")).expect("Failed to parse BMP image");
let pixels: Vec<Pixel> = bmp.into_iter().collect();
//assert_eq!(pixels.len(), 56 * 56);
// Try an outline, top and right
let mut matrix = AniMeImageBuffer::new();
// Aligned left
for (i, px) in pixels.iter().enumerate() {
if (px.x as usize / 2) < WIDTH && (px.y as usize) < HEIGHT && px.x % 2 == 0 {
let mut c = px.color as u32;
matrix.get_mut()[px.y as usize][px.x as usize / 2] = c as u8;
}
}
// Throw an alignment border up
// {
// let tmp = matrix.get_mut();
// for x in tmp[0].iter_mut() {
// *x = 0xff;
// }
// for row in tmp.iter_mut() {
// row[row.len() - 1] = 0xff;
// }
// }
matrix.debug_print();
let mut matrix: AniMePacketType = AniMePacketType::from(matrix);
// println!("{:?}", matrix[0].to_vec());
// println!("{:?}", matrix[1].to_vec());
//client.proxies().anime().set_brightness(&mut matrix).unwrap();
}

View File

@@ -0,0 +1,34 @@
use std::env;
use std::error::Error;
use std::path::Path;
use std::process::exit;
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDiagonal, AnimeType};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
println!("Usage: <filepath> <brightness>");
println!("e.g, asusctl/examples/doom_large.png 0.8");
exit(-1);
}
let matrix = AnimeDiagonal::from_png(
Path::new(&args[1]),
None,
args[2].parse::<f32>().unwrap(),
AnimeType::GA401,
)?;
let anime_type = get_anime_type()?;
proxy.write(matrix.into_data_buffer(anime_type)?).unwrap();
Ok(())
}

View File

@@ -0,0 +1,38 @@
use std::thread::sleep;
use std::time::Duration;
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDiagonal, AnimeType};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data:
// Top row start at 1, ends at 32
// 74w x 36h diagonal used by the windows app
fn main() {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
for step in (2..50).rev() {
let mut matrix = AnimeDiagonal::new(AnimeType::GA401, None);
for c in (0..60).step_by(step) {
for i in matrix.get_mut().iter_mut() {
i[c] = 50;
}
}
for c in (0..35).step_by(step) {
for i in &mut matrix.get_mut()[c] {
*i = 50;
}
}
let anime_type = get_anime_type().unwrap();
proxy
.write(matrix.into_data_buffer(anime_type).unwrap())
.unwrap();
sleep(Duration::from_millis(300));
}
}

View File

@@ -0,0 +1,44 @@
use std::env;
use std::path::Path;
use std::thread::sleep;
use rog_anime::usb::get_anime_type;
use rog_anime::{ActionData, ActionLoader, Sequences};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect();
if args.len() != 3 {
println!("Please supply filepath and brightness");
return;
}
let path = Path::new(&args[1]);
let brightness = args[2].parse::<f32>().unwrap();
let anime_type = get_anime_type().unwrap();
let mut seq = Sequences::new(anime_type);
seq.insert(
0,
&ActionLoader::AsusAnimation {
file: path.into(),
time: rog_anime::AnimTime::Infinite,
brightness,
},
)
.unwrap();
loop {
for action in seq.iter() {
if let ActionData::Animation(frames) = action {
for frame in frames.frames() {
proxy.write(frame.frame().clone()).unwrap();
sleep(frame.delay());
}
}
}
}
}

View File

@@ -0,0 +1,50 @@
use std::convert::TryFrom;
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeGrid};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data:
// Top row start at 1, ends at 32
// 74w x 36h diagonal used by the windows app
fn main() {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let anime_type = get_anime_type().unwrap();
let mut matrix = AnimeGrid::new(anime_type);
let tmp = matrix.get_mut();
let mut i = 0;
for (y, row) in tmp.iter_mut().enumerate() {
if y % 2 == 0 && i + 1 != row.len() - 1 {
i += 1;
}
row[row.len() - i] = 0x22;
if i > 5 {
row[row.len() - i + 5] = 0x22;
}
if i > 10 {
row[row.len() - i + 10] = 0x22;
}
if i > 15 {
row[row.len() - i + 15] = 0x22;
}
if i > 20 {
row[row.len() - i + 20] = 0x22;
}
if i > 25 {
row[row.len() - i + 25] = 0x22;
}
}
let matrix = <AnimeDataBuffer>::try_from(matrix).unwrap();
proxy.write(matrix).unwrap();
}

View File

@@ -0,0 +1,133 @@
use rog_anime::usb::get_anime_type;
use rog_anime::AnimeDataBuffer;
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
// In usable data:
// Top row start at 1, ends at 32
fn main() {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let anime_type = get_anime_type().unwrap();
let mut matrix = AnimeDataBuffer::new(anime_type);
matrix.data_mut()[1] = 100; // start = 1
for n in matrix.data_mut()[2..32].iter_mut() {
*n = 250;
}
matrix.data_mut()[32] = 100; // end
matrix.data_mut()[34] = 100; // start x = 0
matrix.data_mut()[66] = 100; // end
matrix.data_mut()[69] = 100; // start x = 1
matrix.data_mut()[101] = 100; // end
matrix.data_mut()[102] = 100; // start
matrix.data_mut()[134] = 100; // end
matrix.data_mut()[137] = 100; // start
matrix.data_mut()[169] = 100; // end
matrix.data_mut()[170] = 100; // start
matrix.data_mut()[202] = 100; // end
matrix.data_mut()[204] = 100; // start
matrix.data_mut()[236] = 100; // end
matrix.data_mut()[237] = 100; // start
matrix.data_mut()[268] = 100; // end
matrix.data_mut()[270] = 100; // start
matrix.data_mut()[301] = 100; // end
matrix.data_mut()[302] = 100; // start
matrix.data_mut()[332] = 100; // end
matrix.data_mut()[334] = 100; // start
matrix.data_mut()[364] = 100; // end
matrix.data_mut()[365] = 100; // start
matrix.data_mut()[394] = 100; // end
matrix.data_mut()[396] = 100; // start
matrix.data_mut()[425] = 100; // end
matrix.data_mut()[426] = 100; // start
matrix.data_mut()[454] = 100; // end
matrix.data_mut()[456] = 100; // start
matrix.data_mut()[484] = 100; // end
matrix.data_mut()[485] = 100; // start
matrix.data_mut()[512] = 100; // end
matrix.data_mut()[514] = 100; // start
matrix.data_mut()[541] = 100; // end
matrix.data_mut()[542] = 100; // start
matrix.data_mut()[568] = 100; // end
matrix.data_mut()[570] = 100; // start
matrix.data_mut()[596] = 100; // end
matrix.data_mut()[597] = 100; // start
matrix.data_mut()[622] = 100; // end
matrix.data_mut()[624] = 100; // start
matrix.data_mut()[649] = 100; // end
matrix.data_mut()[650] = 100; // start
matrix.data_mut()[674] = 100; // end
matrix.data_mut()[676] = 100; // start
matrix.data_mut()[700] = 100; // end
matrix.data_mut()[701] = 100; // start
matrix.data_mut()[724] = 100; // end
matrix.data_mut()[726] = 100; // start
matrix.data_mut()[749] = 100; // end
matrix.data_mut()[750] = 100; // start
matrix.data_mut()[772] = 100; // end
matrix.data_mut()[774] = 100; // start
matrix.data_mut()[796] = 100; // end
matrix.data_mut()[797] = 100; // start
matrix.data_mut()[818] = 100; // end
matrix.data_mut()[820] = 100; // start
matrix.data_mut()[841] = 100; // end
matrix.data_mut()[842] = 100; // start
matrix.data_mut()[862] = 100; // end
matrix.data_mut()[864] = 100; // start
matrix.data_mut()[884] = 100; // end
matrix.data_mut()[885] = 100; // start
matrix.data_mut()[904] = 100; // end
matrix.data_mut()[906] = 100; // start
matrix.data_mut()[925] = 100; // end
matrix.data_mut()[926] = 100; // start
matrix.data_mut()[944] = 100; // end
matrix.data_mut()[946] = 100; // start
matrix.data_mut()[964] = 100; // end
matrix.data_mut()[965] = 100; // start
matrix.data_mut()[982] = 100; // end
matrix.data_mut()[984] = 100; // start
matrix.data_mut()[1001] = 100; // end
matrix.data_mut()[1002] = 100; // start
matrix.data_mut()[1018] = 100; // end
matrix.data_mut()[1020] = 100; // start
matrix.data_mut()[1036] = 100; // end
matrix.data_mut()[1037] = 100; // start
matrix.data_mut()[1052] = 100; // end
matrix.data_mut()[1054] = 100; // start
matrix.data_mut()[1069] = 100; // end
matrix.data_mut()[1070] = 100; // start
matrix.data_mut()[1084] = 100; // end
matrix.data_mut()[1086] = 100; // start
matrix.data_mut()[1100] = 100; // end
matrix.data_mut()[1101] = 100; // start
matrix.data_mut()[1114] = 100; // end
matrix.data_mut()[1116] = 100; // start
matrix.data_mut()[1129] = 100; // end
matrix.data_mut()[1130] = 100; // start
matrix.data_mut()[1142] = 100; // end
matrix.data_mut()[1144] = 100; // start
matrix.data_mut()[1156] = 100; // end
matrix.data_mut()[1157] = 100; // start
matrix.data_mut()[1168] = 100; // end
matrix.data_mut()[1170] = 100; // start
matrix.data_mut()[1181] = 100; // end
matrix.data_mut()[1182] = 100; // start
matrix.data_mut()[1192] = 100; // end
matrix.data_mut()[1194] = 100; // start
matrix.data_mut()[1204] = 100; // end
matrix.data_mut()[1205] = 100; // start
matrix.data_mut()[1214] = 100; // end
matrix.data_mut()[1216] = 100; // start
matrix.data_mut()[1225] = 100; // end
matrix.data_mut()[1226] = 100; // start
matrix.data_mut()[1234] = 100; // end
matrix.data_mut()[1236] = 100; // start
for n in matrix.data_mut()[1237..1244].iter_mut() {
*n = 250;
}
matrix.data_mut()[1244] = 100; // end
println!("{:?}", &matrix);
proxy.write(matrix).unwrap();
}

View File

@@ -0,0 +1,39 @@
use std::convert::TryFrom;
use std::env;
use std::error::Error;
use std::path::Path;
use std::process::exit;
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect();
if args.len() != 7 {
println!("Usage: <filepath> <scale> <angle> <x pos> <y pos> <brightness>");
println!("e.g, asusctl/examples/doom_large.png 0.9 0.4 0.0 0.0 0.8");
exit(-1);
}
let anime_type = get_anime_type()?;
let matrix = AnimeImage::from_png(
Path::new(&args[1]),
args[2].parse::<f32>().unwrap(),
args[3].parse::<f32>().unwrap(),
Vec2::new(
args[4].parse::<f32>().unwrap(),
args[5].parse::<f32>().unwrap(),
),
args[6].parse::<f32>().unwrap(),
anime_type,
)?;
proxy.write(<AnimeDataBuffer>::try_from(&matrix)?).unwrap();
Ok(())
}

View File

@@ -0,0 +1,49 @@
use std::convert::TryFrom;
use std::env;
use std::error::Error;
use std::f32::consts::PI;
use std::path::Path;
use std::process::exit;
use std::thread::sleep;
use std::time::Duration;
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimeDataBuffer, AnimeImage, Vec2};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn Error>> {
let conn = Connection::system().unwrap();
let proxy = AnimeProxyBlocking::new(&conn).unwrap();
let args: Vec<String> = env::args().collect();
if args.len() != 7 {
println!("Usage: <filepath> <scale> <angle> <x pos> <y pos> <brightness>");
println!("e.g, asusctl/examples/doom_large.png 0.9 0.4 0.0 0.0 0.8");
exit(-1);
}
let anime_type = get_anime_type()?;
let mut matrix = AnimeImage::from_png(
Path::new(&args[1]),
args[2].parse::<f32>().unwrap(),
args[3].parse::<f32>().unwrap(),
Vec2::new(
args[4].parse::<f32>().unwrap(),
args[5].parse::<f32>().unwrap(),
),
args[6].parse::<f32>().unwrap(),
anime_type,
)?;
loop {
matrix.angle += 0.05;
if matrix.angle > PI * 2.0 {
matrix.angle = 0.0;
}
matrix.update();
proxy.write(<AnimeDataBuffer>::try_from(&matrix)?).unwrap();
sleep(Duration::from_micros(500));
}
}

View File

@@ -0,0 +1,113 @@
//! Very bad rushed example. The better way to do this would be to have
//! the balles move on their own square grid, then translate that to the
//! key layout via shape by pitch etc.
use rog_aura::{
layouts::{KeyLayout, KeyRow},
KeyColourArray,
};
use rog_dbus::RogDbusClientBlocking;
use std::collections::VecDeque;
#[derive(Debug, Clone)]
struct Ball {
position: (f32, f32),
direction: (f32, f32),
trail: VecDeque<(f32, f32)>,
}
impl Ball {
fn new(x: f32, y: f32, trail_len: u32) -> Self {
let mut trail = VecDeque::new();
for _ in 1..=trail_len {
trail.push_back((x, y));
}
Ball {
position: (x, y),
direction: (1.0, 1.0),
trail,
}
}
#[allow(clippy::if_same_then_else)]
fn update(&mut self, key_map: &[KeyRow]) {
self.position.0 += self.direction.0;
self.position.1 += self.direction.1;
if self.position.1.abs() as usize >= key_map.len() {
self.direction.1 *= -1.0;
self.position.1 += self.direction.1;
self.direction.0 *= -1.0;
self.position.0 += self.direction.0;
}
if self.position.0.abs() as usize >= key_map[self.position.1.abs() as usize].row_ref().len()
{
self.direction.1 *= -1.0;
self.position.1 += self.direction.1;
}
if self.position.0 as usize >= key_map[self.position.1.abs() as usize].row_ref().len() {
self.direction.0 *= -1.0;
self.position.0 += self.direction.0;
}
let pos = self.position;
if pos.1 == key_map[pos.1.abs() as usize].row_ref().len() as f32 - 1.0 || pos.1 <= 0.0 {
self.direction.0 *= -1.0;
} else if key_map[(pos.1) as usize].row_ref()[(pos.0) as usize].is_placeholder() {
self.direction.0 *= -1.0;
}
if pos.0 == key_map.len() as f32 - 1.0 || pos.0 <= 0.0 {
self.direction.1 *= -1.0;
} else if key_map[(pos.1) as usize].row_ref()[(pos.0) as usize].is_placeholder() {
self.direction.1 *= -1.0;
}
self.trail.pop_front();
self.trail.push_back(self.position);
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = RogDbusClientBlocking::new()?;
let mut colours = KeyColourArray::new();
let layout = KeyLayout::gx502_layout();
let mut balls = [Ball::new(2.0, 1.0, 12), Ball::new(5.0, 2.0, 12)];
// let mut balls = [Ball::new(2, 1, 12)];
loop {
for (n, ball) in balls.iter_mut().enumerate() {
ball.update(layout.rows_ref());
for (i, pos) in ball.trail.iter().enumerate() {
if let Some(c) = colours
.rgb_for_key(layout.rows_ref()[pos.1.abs() as usize].row_ref()[pos.0 as usize])
{
c[0] = 0;
c[1] = 0;
c[2] = 0;
if n == 0 {
c[0] = i as u8 * (255 / ball.trail.len() as u8);
} else if n == 1 {
c[1] = i as u8 * (255 / ball.trail.len() as u8);
} else if n == 2 {
c[2] = i as u8 * (255 / ball.trail.len() as u8);
}
};
}
if let Some(c) = colours.rgb_for_key(
layout.rows_ref()[ball.position.1.abs() as usize].row_ref()
[ball.position.0 as usize],
) {
c[0] = 255;
c[1] = 255;
c[2] = 255;
};
}
dbus.proxies().led().direct_addressing_raw(colours.get())?;
std::thread::sleep(std::time::Duration::from_millis(150));
}
}

View File

@@ -0,0 +1,69 @@
//! Using a combination of key-colour array plus a key layout to generate
//! outputs.
use rog_aura::effects::{AdvancedEffects, Effect};
use rog_aura::keyboard::{KeyLayout, LedCode};
use rog_aura::Colour;
use rog_dbus::zbus_aura::AuraProxyBlocking;
use zbus::blocking::Connection;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let layout = KeyLayout::default_layout();
let conn = Connection::system().unwrap();
let proxy = AuraProxyBlocking::new(&conn).unwrap();
let mut seq = AdvancedEffects::new(true);
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
// RgbAddress::Single,
// Colour(166, 127, 166),
// Colour(127, 155, 20),
// rog_aura::Speed::High,
// ));
// seq.push(zone);
// let zone = Effect::DoomLightFlash(rog_aura::effects::DoomLightFlash::new(
// RgbAddress::Single,
// Colour(200, 0, 0),
// 80,
// 10,
// ));
// seq.push(zone);
let zone = Effect::DoomFlicker(rog_aura::effects::DoomFlicker::new(
LedCode::SingleZone,
Colour {
r: 200,
g: 110,
b: 0,
},
100,
10,
));
seq.push(zone);
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
// RgbAddress::KeyboardCenterLeft,
// Colour(16, 127, 255),
// Colour(127, 15, 20),
// rog_aura::Speed::Low,
// ));
// seq.push(zone);
// let zone = Effect::Breathe(rog_aura::effects::Breathe::new(
// RgbAddress::LightbarRightCorner,
// Colour(0, 255, 255),
// Colour(255, 0, 255),
// rog_aura::Speed::Med,
// ));
// seq.push(zone);
loop {
seq.next_state(&layout);
let packets = seq.create_packets();
proxy.direct_addressing_raw(packets)?;
std::thread::sleep(std::time::Duration::from_millis(33));
}
}

View File

@@ -1,94 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
use std::collections::LinkedList;
#[derive(Debug, Clone)]
struct Ball {
position: (i32, i32),
direction: (i32, i32),
trail: LinkedList<(i32, i32)>,
}
impl Ball {
fn new(x: i32, y: i32, trail_len: u32) -> Self {
let mut trail = LinkedList::new();
for _ in 1..=trail_len {
trail.push_back((x, y));
}
Ball {
position: (x, y),
direction: (1, 1),
trail,
}
}
#[allow(clippy::if_same_then_else)]
fn update(&mut self, key_map: &[[Key; 17]]) {
let pos = self.position;
let dir = self.direction;
if pos.0 + dir.0 > key_map[pos.1 as usize].len() as i32 - 1 || pos.0 + dir.0 < 0 {
self.direction.0 *= -1;
} else if key_map[(pos.1) as usize][(pos.0 + dir.0) as usize] == Key::None {
self.direction.0 *= -1;
}
if pos.1 + dir.1 > key_map.len() as i32 - 1 || pos.1 + dir.1 < 0 {
self.direction.1 *= -1;
} else if key_map[(pos.1 + dir.1) as usize][(pos.0) as usize] == Key::None {
self.direction.1 *= -1;
}
self.trail.pop_front();
self.trail.push_back(self.position);
self.position.0 += self.direction.0;
self.position.1 += self.direction.1;
if self.position.0 > key_map[self.position.1 as usize].len() as i32 {
self.position.0 = key_map[self.position.1 as usize].len() as i32 - 1;
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;
let mut colours = KeyColourArray::new();
let layout = GX502Layout::default();
let mut balls = [Ball::new(2, 1, 12), Ball::new(4, 6, 12)];
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
loop {
for (n, ball) in balls.iter_mut().enumerate() {
ball.update(rows);
for (i, pos) in ball.trail.iter().enumerate() {
if let Some(c) = colours.key(rows[pos.1 as usize][pos.0 as usize]) {
*c.0 = 0;
*c.1 = 0;
*c.2 = 0;
if n == 0 {
*c.0 = i as u8 * (255 / ball.trail.len() as u8);
} else if n == 1 {
*c.1 = i as u8 * (255 / ball.trail.len() as u8);
} else if n == 2 {
*c.2 = i as u8 * (255 / ball.trail.len() as u8);
}
};
}
if let Some(c) = colours.key(rows[ball.position.1 as usize][ball.position.0 as usize]) {
*c.0 = 255;
*c.1 = 255;
*c.2 = 255;
};
}
dbus.proxies().led().set_per_key(&colours)?;
std::thread::sleep(std::time::Duration::from_millis(10));
}
}

View File

@@ -1,28 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;
let layout = GX502Layout::default();
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
let mut column = 0;
loop {
let mut key_colours = KeyColourArray::new();
for row in rows {
if let Some(c) = key_colours.key(row[column as usize]) {
*c.0 = 255;
};
}
if column == rows[0].len() - 1 {
column = 0
} else {
column += 1;
}
dbus.proxies().led().set_per_key(&key_colours)?;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
asusctl/examples/doom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

BIN
asusctl/examples/ferris.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@@ -1,54 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, Key, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default();
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
loop {
for (r, row) in rows.iter().enumerate() {
for (k, key) in row.iter().enumerate() {
if let Some(c) = key_colours.key(*key) {
*c.0 = 255;
};
// Last key of previous row
if k == 0 {
if r == 0 {
let k = &rows[rows.len() - 1][rows[rows.len() - 1].len() - 1];
if let Some(c) = key_colours.key(*k) {
*c.0 = 0;
};
} else {
let k = &rows[r - 1][rows[r - 1].len() - 1];
if let Some(c) = key_colours.key(*k) {
*c.0 = 0;
};
}
} else {
let k = &rows[r][k - 1];
if let Some(c) = key_colours.key(*k) {
*c.0 = 0;
};
}
if let Some(c) = key_colours.key(Key::Up) {
*c.0 = 255;
};
*key_colours.key(Key::Left).unwrap().0 = 255;
*key_colours.key(Key::Right).unwrap().0 = 255;
*key_colours.key(Key::Down).unwrap().0 = 255;
*key_colours.key(Key::W).unwrap().0 = 255;
*key_colours.key(Key::A).unwrap().0 = 255;
*key_colours.key(Key::S).unwrap().0 = 255;
*key_colours.key(Key::D).unwrap().0 = 255;
dbus.proxies().led().set_per_key(&key_colours)?;
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

BIN
asusctl/examples/nudoom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -1,31 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{Key, KeyColourArray};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
dbus.proxies().led().init_effect()?;
loop {
let count = 49;
for _ in 0..count {
*key_colours.key(Key::ROG).unwrap().0 += 5;
*key_colours.key(Key::L).unwrap().0 += 5;
*key_colours.key(Key::I).unwrap().0 += 5;
*key_colours.key(Key::N).unwrap().0 += 5;
*key_colours.key(Key::U).unwrap().0 += 5;
*key_colours.key(Key::X).unwrap().0 += 5;
dbus.proxies().led().set_per_key(&key_colours)?;
}
for _ in 0..count {
*key_colours.key(Key::ROG).unwrap().0 -= 5;
*key_colours.key(Key::L).unwrap().0 -= 5;
*key_colours.key(Key::I).unwrap().0 -= 5;
*key_colours.key(Key::N).unwrap().0 -= 5;
*key_colours.key(Key::U).unwrap().0 -= 5;
*key_colours.key(Key::X).unwrap().0 -= 5;
dbus.proxies().led().set_per_key(&key_colours)?;
}
}
}

View File

@@ -1,38 +0,0 @@
use rog_dbus::AuraDbusClient;
use rog_types::aura_perkey::{GX502Layout, KeyColourArray, KeyLayout};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let (dbus, _) = AuraDbusClient::new()?;
let mut key_colours = KeyColourArray::new();
let layout = GX502Layout::default();
dbus.proxies().led().init_effect()?;
let rows = layout.get_rows();
let mut fade = 50;
let mut flip = false;
loop {
for row in rows {
for (k, key) in row.iter().enumerate() {
if let Some(c) = key_colours.key(*key) {
*c.0 = 255 / fade / (k + 1) as u8;
};
}
}
dbus.proxies().led().set_per_key(&key_colours)?;
if flip {
if fade > 1 {
fade -= 1;
} else {
flip = !flip;
}
} else if fade < 17 {
fade += 1;
} else {
flip = !flip;
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

BIN
asusctl/examples/rust.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

154
asusctl/src/anime_cli.rs Normal file
View File

@@ -0,0 +1,154 @@
use gumdrop::Options;
use rog_anime::usb::{AnimAwake, AnimBooting, AnimShutdown, AnimSleeping, Brightness};
use rog_anime::AnimeType;
#[derive(Options)]
pub struct AnimeCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "override the display type")]
pub override_type: Option<AnimeType>,
#[options(meta = "", help = "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>"
)]
pub brightness: Option<Brightness>,
#[options(help = "clear the display")]
pub clear: bool,
#[options(
no_short,
meta = "",
help = "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"
)]
pub off_when_suspended: Option<bool>,
#[options(
no_short,
meta = "",
help = "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!!!")]
pub off_with_his_head: Option<bool>,
#[options(command)]
pub command: Option<AnimeActions>,
}
#[derive(Options)]
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)]
pub struct Builtins {
#[options(help = "print help message")]
pub help: bool,
#[options(
meta = "",
help = "Default is used if unspecified, <default:GlitchConstruction, StaticEmergence>"
)]
pub boot: AnimBooting,
#[options(
meta = "",
help = "Default is used if unspecified, <default:BinaryBannerScroll, RogLogoGlitch>"
)]
pub awake: AnimAwake,
#[options(
meta = "",
help = "Default is used if unspecified, <default:BannerSwipe, Starfield>"
)]
pub sleep: AnimSleeping,
#[options(
meta = "",
help = "Default is used if unspecified, <default:GlitchOut, SeeYa>"
)]
pub shutdown: AnimShutdown,
#[options(meta = "", help = "set/apply the animations <true/false>")]
pub set: Option<bool>,
}
#[derive(Options)]
pub struct AnimeImage {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "scale 1.0 == normal")]
pub scale: f32,
#[options(meta = "", default = "0.0", help = "x position (float)")]
pub x_pos: f32,
#[options(meta = "", default = "0.0", help = "y position (float)")]
pub y_pos: f32,
#[options(meta = "", default = "0.0", help = "the angle in radians")]
pub angle: f32,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32,
}
#[derive(Options)]
pub struct AnimeImageDiagonal {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32,
}
#[derive(Options)]
pub struct AnimeGif {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "scale 1.0 == normal")]
pub scale: f32,
#[options(meta = "", default = "0.0", help = "x position (float)")]
pub x_pos: f32,
#[options(meta = "", default = "0.0", help = "y position (float)")]
pub y_pos: f32,
#[options(meta = "", default = "0.0", help = "the angle in radians")]
pub angle: f32,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}
#[derive(Options)]
pub struct AnimeGifDiagonal {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "full path to the png to display")]
pub path: String,
#[options(meta = "", default = "1.0", help = "brightness 0.0-1.0")]
pub bright: f32,
#[options(
meta = "",
default = "1",
help = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
}

View File

@@ -1,25 +1,77 @@
use gumdrop::Options;
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed},
error::AuraError,
};
use std::str::FromStr;
use gumdrop::Options;
use rog_aura::error::Error;
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
#[derive(Options, Debug)]
pub struct LedPowerCommand1 {
#[options(help = "print help message")]
pub help: bool,
#[options(meta = "", help = "Control if LEDs enabled while awake <true/false>")]
pub awake: Option<bool>,
#[options(help = "Use with awake option, if excluded defaults to false")]
pub keyboard: bool,
#[options(help = "Use with awake option, if excluded defaults to false")]
pub lightbar: bool,
#[options(meta = "", help = "Control boot animations <true/false>")]
pub boot: Option<bool>,
#[options(meta = "", help = "Control suspend animations <true/false>")]
pub sleep: Option<bool>,
}
#[derive(Options, Debug)]
pub struct LedPowerCommand2 {
#[options(help = "print help message")]
pub help: bool,
#[options(command)]
pub command: Option<SetAuraZoneEnabled>,
}
#[derive(Options, Debug)]
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),
}
#[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)]
pub struct LedBrightness {
level: Option<u32>,
level: Option<u8>,
}
impl LedBrightness {
pub fn new(level: Option<u32>) -> Self {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u32> {
pub fn level(&self) -> Option<u8> {
self.level
}
}
impl FromStr for LedBrightness {
type Err = AuraError;
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
@@ -30,11 +82,12 @@ impl FromStr for LedBrightness {
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
print!("Invalid argument, must be one of: off, low, med, high");
Err(AuraError::ParseBrightness)
Err(Error::ParseBrightness)
}
}
}
}
#[allow(clippy::to_string_trait_impl)]
impl ToString for LedBrightness {
fn to_string(&self) -> String {
let s = match self.level {
@@ -43,7 +96,7 @@ impl ToString for LedBrightness {
Some(0x02) => "high",
_ => "unknown",
};
s.to_string()
s.to_owned()
}
}
@@ -53,7 +106,14 @@ pub struct SingleSpeed {
help: bool,
#[options(no_long, meta = "WORD", help = "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"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Options, Default)]
pub struct SingleSpeedDirection {
#[options(help = "print help message")]
@@ -62,6 +122,12 @@ pub struct SingleSpeedDirection {
pub direction: Direction,
#[options(no_long, meta = "", help = "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"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
@@ -70,6 +136,12 @@ pub struct SingleColour {
help: bool,
#[options(no_long, meta = "", help = "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"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
@@ -80,6 +152,12 @@ pub struct SingleColourSpeed {
pub colour: Colour,
#[options(no_long, meta = "", help = "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"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Options, Default)]
@@ -92,10 +170,16 @@ pub struct TwoColourSpeed {
pub colour2: Colour,
#[options(no_long, meta = "", help = "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"
)]
pub zone: AuraZone,
}
#[derive(Debug, Clone, Default, Options)]
pub struct MultiColour {
pub struct MultiZone {
#[options(help = "print help message")]
help: bool,
#[options(short = "a", meta = "", help = "set the RGB value e.g, ff00ff")]
@@ -127,36 +211,33 @@ pub struct MultiColourSpeed {
/// Byte value for setting the built-in mode.
///
/// Enum corresponds to the required integer value
// NOTE: The option names here must match those in rog-aura crate
#[derive(Options)]
pub enum SetAuraBuiltin {
#[options(help = "set a single static colour")]
Static(SingleColour),
Static(SingleColour), // 0
#[options(help = "pulse between one or two colours")]
Breathe(TwoColourSpeed),
Breathe(TwoColourSpeed), // 1
#[options(help = "strobe through all colours")]
Strobe(SingleSpeed),
Strobe(SingleSpeed), // 2
#[options(help = "rainbow cycling in one of four directions")]
Rainbow(SingleSpeedDirection),
Rainbow(SingleSpeedDirection), // 3
#[options(help = "rain pattern mimicking raindrops")]
Star(TwoColourSpeed),
Stars(TwoColourSpeed), // 4
#[options(help = "rain pattern of three preset colours")]
Rain(SingleSpeed),
Rain(SingleSpeed), // 5
#[options(help = "pressed keys are highlighted to fade")]
Highlight(SingleColourSpeed),
Highlight(SingleColourSpeed), // 6
#[options(help = "pressed keys generate horizontal laser")]
Laser(SingleColourSpeed),
Laser(SingleColourSpeed), // 7
#[options(help = "pressed keys ripple outwards like a splash")]
Ripple(SingleColourSpeed),
Ripple(SingleColourSpeed), // 8
#[options(help = "set a rapid pulse")]
Pulse(SingleColour),
Pulse(SingleColour), // 10
#[options(help = "set a vertical line zooming from left")]
Comet(SingleColour),
Comet(SingleColour), // 11
#[options(help = "set a wide vertical line zooming from left")]
Flash(SingleColour),
#[options(help = "4-zone multi-colour")]
MultiStatic(MultiColour),
#[options(help = "4-zone multi-colour breathing")]
MultiBreathe(MultiColourSpeed),
Flash(SingleColour), // 12
}
impl Default for SetAuraBuiltin {
@@ -169,6 +250,7 @@ impl From<&SingleColour> for AuraEffect {
fn from(aura: &SingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
@@ -178,6 +260,7 @@ impl From<&SingleSpeed> for AuraEffect {
fn from(aura: &SingleSpeed) -> Self {
Self {
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
@@ -188,6 +271,7 @@ impl From<&SingleColourSpeed> for AuraEffect {
Self {
colour1: aura.colour,
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
@@ -198,6 +282,7 @@ impl From<&TwoColourSpeed> for AuraEffect {
Self {
colour1: aura.colour,
colour2: aura.colour2,
zone: aura.zone,
..Default::default()
}
}
@@ -208,6 +293,7 @@ impl From<&SingleSpeedDirection> for AuraEffect {
Self {
speed: aura.speed,
direction: aura.direction,
zone: aura.zone,
..Default::default()
}
}
@@ -236,7 +322,7 @@ impl From<&SetAuraBuiltin> for AuraEffect {
data.mode = AuraModeNum::Rainbow;
data
}
SetAuraBuiltin::Star(x) => {
SetAuraBuiltin::Stars(x) => {
let mut data: AuraEffect = x.into();
data.mode = AuraModeNum::Star;
data
@@ -276,55 +362,6 @@ impl From<&SetAuraBuiltin> for AuraEffect {
data.mode = AuraModeNum::Flash;
data
}
_ => AuraEffect::default(),
}
}
}
impl From<&SetAuraBuiltin> for Vec<AuraEffect> {
fn from(aura: &SetAuraBuiltin) -> Vec<AuraEffect> {
let mut zones = vec![AuraEffect::default(); 4];
match aura {
SetAuraBuiltin::MultiStatic(data) => {
zones[0].mode = AuraModeNum::Static;
zones[0].zone = AuraZone::One;
zones[0].colour1 = data.colour1;
zones[1].mode = AuraModeNum::Static;
zones[1].zone = AuraZone::Two;
zones[1].colour1 = data.colour2;
zones[2].mode = AuraModeNum::Static;
zones[2].zone = AuraZone::Three;
zones[2].colour1 = data.colour3;
zones[3].mode = AuraModeNum::Static;
zones[3].zone = AuraZone::Four;
zones[3].colour1 = data.colour4;
}
SetAuraBuiltin::MultiBreathe(data) => {
zones[0].mode = AuraModeNum::Breathe;
zones[0].zone = AuraZone::One;
zones[0].colour1 = data.colour1;
zones[0].speed = data.speed;
zones[1].mode = AuraModeNum::Breathe;
zones[1].zone = AuraZone::Two;
zones[1].colour1 = data.colour2;
zones[1].speed = data.speed;
zones[2].mode = AuraModeNum::Breathe;
zones[2].zone = AuraZone::Three;
zones[2].colour1 = data.colour3;
zones[2].speed = data.speed;
zones[3].mode = AuraModeNum::Breathe;
zones[3].zone = AuraZone::Four;
zones[3].colour1 = data.colour4;
zones[3].speed = data.speed;
}
_ => {}
}
zones
}
}

118
asusctl/src/cli_opts.rs Normal file
View File

@@ -0,0 +1,118 @@
use gumdrop::Options;
use rog_platform::platform::ThrottlePolicy;
use crate::anime_cli::AnimeCommand;
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
use crate::fan_curve_cli::FanCurveCommand;
use crate::slash_cli::SlashCommand;
#[derive(Default, 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(command)]
pub command: Option<CliCommand>,
}
#[derive(Options)]
pub enum CliCommand {
#[options(help = "Set the keyboard lighting from built-in modes")]
LedMode(LedModeCommand),
#[options(help = "Set the LED power states")]
LedPow1(LedPowerCommand1),
#[options(help = "Set the LED power states")]
LedPow2(LedPowerCommand2),
#[options(help = "Set or select platform_profile")]
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(help = "Change bios settings")]
Bios(BiosCommand),
}
#[derive(Debug, Clone, Options)]
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>,
}
#[derive(Options)]
pub struct LedModeCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "switch to next aura mode")]
pub next_mode: bool,
#[options(help = "switch to previous aura mode")]
pub prev_mode: bool,
#[options(command)]
pub command: Option<SetAuraBuiltin>,
}
#[derive(Options)]
pub struct GraphicsCommand {
#[options(help = "print help message")]
pub help: bool,
}
#[derive(Options, Debug)]
pub struct BiosCommand {
#[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,
}

View File

@@ -0,0 +1,49 @@
use gumdrop::Options;
use rog_platform::platform::ThrottlePolicy;
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::FanCurvePU;
#[derive(Debug, Clone, Options)]
pub struct FanCurveCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "get enabled fan profiles")]
pub get_enabled: bool,
#[options(help = "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"
)]
pub mod_profile: Option<ThrottlePolicy>,
#[options(
meta = "",
help = "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"
)]
pub enable_fan_curve: Option<bool>,
#[options(
meta = "",
help = "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"
)]
pub data: Option<CurveData>,
}

File diff suppressed because it is too large Load Diff

20
asusctl/src/slash_cli.rs Normal file
View File

@@ -0,0 +1,20 @@
use gumdrop::Options;
use rog_slash::SlashMode;
#[derive(Options)]
pub struct SlashCommand {
#[options(help = "print help message")]
pub help: bool,
#[options(help = "Enable the Slash Ledbar")]
pub enable: bool,
#[options(help = "Ddisable the Slash Ledbar")]
pub disable: bool,
#[options(meta = "", help = "Set brightness value <0-255>")]
pub brightness: Option<u8>,
#[options(meta = "", help = "Set interval value <0-255>")]
pub interval: Option<u8>,
#[options(help = "Set SlashMode (so 'list' for all options)")]
pub slash_mode: Option<SlashMode>,
#[options(help = "list available animations")]
pub list: bool,
}

37
asusd-user/Cargo.toml Normal file
View File

@@ -0,0 +1,37 @@
[package]
name = "asusd-user"
license.workspace = true
version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[[bin]]
name = "asusd-user"
path = "src/daemon.rs"
[dependencies]
dirs.workspace = true
smol.workspace = true
# serialisation
serde.workspace = true
serde_derive.workspace = true
ron.workspace = true
rog_anime = { path = "../rog-anime" }
rog_aura = { path = "../rog-aura" }
rog_dbus = { path = "../rog-dbus" }
rog_platform = { path = "../rog-platform" }
config-traits = { path = "../config-traits" }
zbus.workspace = true
env_logger.workspace = true
[dev-dependencies]
cargo-husky.workspace = true
[package.metadata.cargo-machete]
ignored = ["serde"]

14
asusd-user/README.md Normal file
View File

@@ -0,0 +1,14 @@
# daemon-user
This crate is for the binary of `asusd-user` and its helper lib.
The purpose of `asusd-user` is to run in userland and provide the user + third-party apps an interface for such things as creating AniMe sequences (and more in future, see todo list).
`asusd-user` should try to be as simple as possible while allowing a decent degree of control.
## TODO
- [ ] CLI for basic settings/interaction
- [ ] RGB keyboard per-key programs
- [ ] User profiles (fan, cpu etc). These would be replacing the system-daemon profiles only when the user is active, otherwise system-daemon defaults to system settings.
- [ ] Audio EQ visualiser - for use with anime + keyboard lighting

232
asusd-user/src/config.rs Normal file
View File

@@ -0,0 +1,232 @@
use std::path::PathBuf;
use std::time::Duration;
use config_traits::{StdConfig, StdConfigLoad};
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences as AnimeSequences, Vec2};
use rog_aura::effects::{AdvancedEffects as AuraSequences, Breathe, DoomFlicker, Effect, Static};
use rog_aura::keyboard::LedCode;
use rog_aura::{Colour, Speed};
use serde_derive::{Deserialize, Serialize};
use crate::error::Error;
const ROOT_CONF_DIR: &str = "rog";
fn root_conf_dir() -> PathBuf {
let mut dir = dirs::config_dir().unwrap_or_else(|| PathBuf::from("/tmp"));
dir.push(ROOT_CONF_DIR);
dir
}
#[derive(Debug, Deserialize, Serialize)]
pub struct ConfigAnime {
pub name: String,
pub anime: Vec<ActionLoader>,
}
impl ConfigAnime {
pub fn create(&self, anime_type: AnimeType) -> Result<AnimeSequences, Error> {
let mut seq = AnimeSequences::new(anime_type);
for (idx, action) in self.anime.iter().enumerate() {
seq.insert(idx, action)?;
}
Ok(seq)
}
pub fn set_name(mut self, name: String) -> Self {
self.name = name;
self
}
}
impl Default for ConfigAnime {
fn default() -> Self {
Self {
name: "anime-default".to_owned(),
anime: vec![
ActionLoader::AsusImage {
file: "/usr/share/asusd/anime/custom/diagonal-template.png".into(),
brightness: 1.0,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
None,
Duration::from_secs(2),
)),
},
ActionLoader::AsusAnimation {
file: "/usr/share/asusd/anime/asus/rog/Sunset.gif".into(),
brightness: 0.5,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(6),
None,
Duration::from_secs(3),
)),
},
ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-run.gif".into(),
scale: 0.9,
angle: 0.65,
translation: Vec2::default(),
brightness: 0.5,
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(2)),
Duration::from_secs(2),
)),
},
ActionLoader::Image {
file: "/usr/share/asusd/anime/custom/rust.png".into(),
scale: 1.0,
angle: 0.0,
translation: Vec2::default(),
time: AnimTime::Fade(Fade::new(
Duration::from_secs(2),
Some(Duration::from_secs(1)),
Duration::from_secs(2),
)),
brightness: 0.6,
},
ActionLoader::Pause(Duration::from_secs(1)),
ActionLoader::ImageAnimation {
file: "/usr/share/asusd/anime/custom/sonic-wait.gif".into(),
scale: 0.9,
angle: 0.0,
translation: Vec2::new(3.0, 2.0),
brightness: 0.5,
time: AnimTime::Count(2),
},
],
}
}
}
impl StdConfig for ConfigAnime {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
format!("{}.ron", self.name)
}
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad for ConfigAnime {}
#[derive(Debug, Deserialize, Serialize)]
pub struct ConfigAura {
pub name: String,
pub aura: AuraSequences,
}
impl ConfigAura {
pub fn set_name(mut self, name: String) -> Self {
self.name = name;
self
}
}
impl Default for ConfigAura {
fn default() -> Self {
let mut seq = AuraSequences::new(false);
let mut key = Effect::Breathe(Breathe::new(
LedCode::W,
Colour {
r: 255,
g: 0,
b: 20,
},
Colour {
r: 20,
g: 255,
b: 0,
},
Speed::Low,
));
seq.push(key.clone());
key.set_led(LedCode::A);
seq.push(key.clone());
key.set_led(LedCode::S);
seq.push(key.clone());
key.set_led(LedCode::D);
seq.push(key);
let key = Effect::Breathe(Breathe::new(
LedCode::F,
Colour { r: 255, g: 0, b: 0 },
Colour { r: 255, g: 0, b: 0 },
Speed::High,
));
seq.push(key);
let mut key = Effect::Static(Static::new(LedCode::RCtrl, Colour { r: 0, g: 0, b: 255 }));
seq.push(key.clone());
key.set_led(LedCode::LCtrl);
seq.push(key.clone());
key.set_led(LedCode::Esc);
seq.push(key);
let key = Effect::DoomFlicker(DoomFlicker::new(
LedCode::N9,
Colour { r: 0, g: 0, b: 255 },
80,
40,
));
seq.push(key);
Self {
name: "aura-default".to_owned(),
aura: seq,
}
}
}
impl StdConfig for ConfigAura {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
format!("{}.ron", self.name)
}
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad for ConfigAura {}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(default)]
pub struct ConfigBase {
/// Name of active anime config file in the user config directory
pub active_anime: Option<String>,
/// Name of active aura config file in the user config directory
pub active_aura: Option<String>,
}
impl StdConfig for ConfigBase {
fn new() -> Self {
Self {
active_anime: Some("anime-default".to_owned()),
active_aura: Some("aura-default".to_owned()),
}
}
fn file_name(&self) -> String {
"rog-user.ron".to_owned()
}
fn config_dir() -> std::path::PathBuf {
root_conf_dir()
}
}
impl StdConfigLoad for ConfigBase {}

View File

@@ -0,0 +1,361 @@
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::thread::sleep;
use std::time::{Duration, Instant};
use config_traits::StdConfig;
use rog_anime::error::AnimeError;
use rog_anime::{ActionData, ActionLoader, AnimTime, Fade, Sequences, Vec2};
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use ron::ser::PrettyConfig;
use serde_derive::{Deserialize, Serialize};
use zbus::interface;
use zbus::zvariant::{ObjectPath, Type};
use crate::config::ConfigAnime;
use crate::error::Error;
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
pub struct Timer {
type_of: TimeType,
/// If time type is Timer then this is milliseonds, otherwise it is
/// animation loop count
count: u64,
/// Used only for `TimeType::Timer`, milliseonds to fade the image in for
fade_in: u64,
/// Used only for `TimeType::Timer`, milliseonds to fade the image out for
fade_out: u64,
}
impl From<Timer> for AnimTime {
fn from(time: Timer) -> Self {
match time.type_of {
TimeType::Timer => {
if time.fade_in != 0 && time.fade_out != 0 {
let fade_in = Duration::from_millis(time.fade_in);
let fade_out = Duration::from_millis(time.fade_out);
let show_for = if time.count != 0 {
Some(Duration::from_millis(time.count))
} else {
None
};
AnimTime::Fade(Fade::new(fade_in, show_for, fade_out))
} else {
AnimTime::Time(Duration::from_millis(time.count))
}
}
TimeType::Count => AnimTime::Count(time.count as u32),
TimeType::Infinite => AnimTime::Infinite,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, Type)]
pub enum TimeType {
Timer,
Count,
Infinite,
}
/// The inner object exists to allow the zbus proxy to share it with a runner
/// thread and a zbus server behind `Arc<Mutex<T>>`
pub struct CtrlAnimeInner<'a> {
sequences: Sequences,
client: AnimeProxyBlocking<'a>,
do_early_return: Arc<AtomicBool>,
}
impl<'a> CtrlAnimeInner<'static> {
pub fn new(
sequences: Sequences,
client: AnimeProxyBlocking<'static>,
do_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> {
Ok(Self {
sequences,
client,
do_early_return,
})
}
/// To be called on each main loop iteration to pump out commands to the
/// anime
pub fn run(&'a self) -> Result<(), Error> {
if self.do_early_return.load(Ordering::SeqCst) {
return Ok(());
}
for action in self.sequences.iter() {
match action {
ActionData::Animation(frames) => {
rog_anime::run_animation(frames, &|output| {
if self.do_early_return.load(Ordering::Acquire) {
return Ok(true); // Do safe exit
}
self.client
.write(output)
.map_err(|e| AnimeError::Dbus(format!("{}", e)))
.map(|_| false)
});
}
ActionData::Image(image) => {
self.client.write(image.as_ref().clone()).ok();
}
ActionData::Pause(duration) => {
let start = Instant::now();
'pause: loop {
if self.do_early_return.load(Ordering::SeqCst) {
return Ok(());
}
if Instant::now().duration_since(start) > *duration {
break 'pause;
}
sleep(Duration::from_millis(1));
}
}
ActionData::AudioEq
| ActionData::SystemInfo
| ActionData::TimeDate
| ActionData::Matrix => {}
}
}
Ok(())
}
}
pub struct CtrlAnime<'a> {
config: Arc<Mutex<ConfigAnime>>,
client: AnimeProxyBlocking<'a>,
inner: Arc<Mutex<CtrlAnimeInner<'a>>>,
/// Must be the same Atomic as in CtrlAnimeInner
inner_early_return: Arc<AtomicBool>,
}
impl CtrlAnime<'static> {
pub fn new(
config: Arc<Mutex<ConfigAnime>>,
inner: Arc<Mutex<CtrlAnimeInner<'static>>>,
client: AnimeProxyBlocking<'static>,
inner_early_return: Arc<AtomicBool>,
) -> Result<Self, Error> {
Ok(CtrlAnime {
config,
client,
inner,
inner_early_return,
})
}
pub async fn add_to_server(self, server: &mut zbus::Connection) {
server
.object_server()
.at(
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
self,
)
.await
.map_err(|err| {
println!("CtrlAnime: add_to_server {}", err);
err
})
.ok();
}
}
// The pattern for a zbus method is:
// - Get config lock if required
// - Set inner_early_return to stop the inner run loop temporarily
// - Do actions
// - Write config if required
// - Unset inner_early_return
#[interface(name = "org.asuslinux.Daemon")]
impl CtrlAnime<'static> {
pub fn insert_asus_gif(
&mut self,
index: u32,
file: &str,
time: Timer,
brightness: f32,
) -> zbus::fdo::Result<String> {
if let Ok(mut config) = self.config.try_lock() {
let time: AnimTime = time.into();
let file = Path::new(&file);
let action = ActionLoader::AsusAnimation {
file: file.into(),
brightness,
time,
};
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() {
controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write();
let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(ron);
}
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
}
#[allow(clippy::too_many_arguments)]
pub fn insert_image_gif(
&mut self,
index: u32,
file: &str,
scale: f32,
angle: f32,
xy: (f32, f32),
time: Timer,
brightness: f32,
) -> zbus::fdo::Result<String> {
if let Ok(mut config) = self.config.try_lock() {
let time: AnimTime = time.into();
let file = Path::new(&file);
let translation = Vec2::new(xy.0, xy.1);
let action = ActionLoader::ImageAnimation {
file: file.into(),
scale,
angle,
translation,
brightness,
time,
};
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() {
controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write();
let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(ron);
}
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
}
#[allow(clippy::too_many_arguments)]
pub fn insert_image(
&mut self,
index: u32,
file: &str,
scale: f32,
angle: f32,
xy: (f32, f32),
time: Timer,
brightness: f32,
) -> zbus::fdo::Result<String> {
if let Ok(mut config) = self.config.try_lock() {
let file = Path::new(&file);
let time = time.into();
let action = ActionLoader::Image {
file: file.into(),
scale,
angle,
translation: Vec2::new(xy.0, xy.1),
brightness,
time,
};
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() {
controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write();
let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(ron);
}
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
}
pub fn insert_pause(&mut self, index: u32, millis: u64) -> zbus::fdo::Result<String> {
if let Ok(mut config) = self.config.try_lock() {
let action = ActionLoader::Pause(Duration::from_millis(millis));
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() {
controller
.sequences
.insert(index as usize, &action)
.map_err(|err| zbus::fdo::Error::Failed(err.to_string()))?;
}
config.anime.push(action);
config.write();
let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(ron);
}
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
}
pub fn remove_item(&mut self, index: u32) -> zbus::fdo::Result<String> {
if let Ok(mut config) = self.config.try_lock() {
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
if let Ok(mut controller) = self.inner.lock() {
controller.sequences.remove_item(index as usize);
}
if (index as usize) < config.anime.len() {
config.anime.remove(index as usize);
}
config.write();
let ron = ron::ser::to_string_pretty(&*config, PrettyConfig::new().depth_limit(4))
.expect("Parse config to RON failed");
// Release the inner run loop again
self.inner_early_return.store(false, Ordering::SeqCst);
return Ok(ron);
}
Err(zbus::fdo::Error::Failed("UserConfig lock fail".into()))
}
pub fn set_state(&mut self, on: bool) -> zbus::fdo::Result<()> {
// Operations here need to be in specific order
if on {
self.client.set_enable_display(on).ok();
// Let the inner loop run
self.inner_early_return.store(false, Ordering::SeqCst);
} else {
// Must make the inner run loop return early
self.inner_early_return.store(true, Ordering::SeqCst);
self.client.set_enable_display(on).ok();
}
Ok(())
}
}

123
asusd-user/src/daemon.rs Normal file
View File

@@ -0,0 +1,123 @@
use std::io::Write;
use std::path::PathBuf;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
use asusd_user::config::*;
use asusd_user::ctrl_anime::{CtrlAnime, CtrlAnimeInner};
use config_traits::{StdConfig, StdConfigLoad};
use rog_anime::usb::get_anime_type;
use rog_aura::aura_detection::LedSupportData;
use rog_aura::keyboard::KeyLayout;
use rog_dbus::zbus_anime::AnimeProxyBlocking;
use rog_dbus::zbus_aura::AuraProxyBlocking;
use rog_dbus::zbus_platform::PlatformProxyBlocking;
use rog_dbus::DBUS_NAME;
use smol::Executor;
use zbus::Connection;
#[cfg(not(feature = "local_data"))]
const DATA_DIR: &str = "/usr/share/rog-gui/";
#[cfg(feature = "local_data")]
const DATA_DIR: &str = env!("CARGO_MANIFEST_DIR");
const BOARD_NAME: &str = "/sys/class/dmi/id/board_name";
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.init();
println!(" user daemon v{}", asusd_user::VERSION);
println!(" rog-anime v{}", rog_anime::VERSION);
println!(" rog-dbus v{}", rog_dbus::VERSION);
println!("rog-platform v{}", rog_platform::VERSION);
let conn = zbus::blocking::Connection::system().unwrap();
let platform_proxy = PlatformProxyBlocking::new(&conn).unwrap();
let supported = platform_proxy
.supported_interfaces()
.unwrap_or_default()
.contains(&"Anime".to_string());
let config = ConfigBase::new().load();
let executor = Executor::new();
let early_return = Arc::new(AtomicBool::new(false));
// Set up the anime data and run loop/thread
if supported {
if let Some(cfg) = config.active_anime {
let anime_type = get_anime_type()?;
let anime_config = ConfigAnime::new().set_name(cfg).load();
let anime = anime_config.create(anime_type)?;
let anime_config = Arc::new(Mutex::new(anime_config));
let anime_proxy_blocking = AnimeProxyBlocking::new(&conn).unwrap();
executor
.spawn(async move {
// Create server
let mut connection = Connection::session().await.unwrap();
connection.request_name(DBUS_NAME).await.unwrap();
// Inner behind mutex required for thread safety
let inner = Arc::new(Mutex::new(
CtrlAnimeInner::new(
anime,
anime_proxy_blocking.clone(),
early_return.clone(),
)
.unwrap(),
));
// Need new client object for dbus control part
let anime_control = CtrlAnime::new(
anime_config,
inner.clone(),
anime_proxy_blocking,
early_return,
)
.unwrap();
anime_control.add_to_server(&mut connection).await;
loop {
if let Ok(inner) = inner.clone().try_lock() {
inner.run().ok();
}
}
})
.detach();
}
}
// if supported.keyboard_led.per_key_led_mode {
if let Some(cfg) = config.active_aura {
let mut aura_config = ConfigAura::new().set_name(cfg).load();
// let baord_name = std::fs::read_to_string(BOARD_NAME)?;
let led_support = LedSupportData::get_data("");
let layout = KeyLayout::find_layout(led_support, PathBuf::from(DATA_DIR))
.map_err(|e| {
println!("{BOARD_NAME}, {e}");
})
.unwrap_or_else(|_| KeyLayout::default_layout());
let aura_proxy_blocking = AuraProxyBlocking::new(&conn).unwrap();
executor
.spawn(async move {
loop {
aura_config.aura.next_state(&layout);
let packets = aura_config.aura.create_packets();
aura_proxy_blocking.direct_addressing_raw(packets).unwrap();
std::thread::sleep(std::time::Duration::from_millis(33));
}
})
.detach();
}
// }
loop {
smol::block_on(executor.tick());
}
}

45
asusd-user/src/error.rs Normal file
View File

@@ -0,0 +1,45 @@
use std::fmt;
use rog_anime::error::AnimeError;
#[derive(Debug)]
pub enum Error {
Io(std::io::Error),
ConfigLoadFail,
ConfigLockFail,
XdgVars,
Anime(AnimeError),
}
impl fmt::Display for Error {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Io(err) => write!(f, "Failed to open: {}", err),
Error::ConfigLoadFail => write!(f, "Failed to load user config"),
Error::ConfigLockFail => write!(f, "Failed to lock user config"),
Error::XdgVars => write!(f, "XDG environment vars appear unset"),
Error::Anime(err) => write!(f, "Anime error: {}", err),
}
}
}
impl std::error::Error for Error {}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err)
}
}
impl From<AnimeError> for Error {
fn from(err: AnimeError) -> Self {
Error::Anime(err)
}
}
impl From<Error> for zbus::fdo::Error {
fn from(err: Error) -> Self {
zbus::fdo::Error::Failed(format!("Anime zbus error: {}", err))
}
}

9
asusd-user/src/lib.rs Normal file
View File

@@ -0,0 +1,9 @@
pub mod config;
pub mod error;
pub mod ctrl_anime;
pub mod zbus_anime;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");

View File

@@ -0,0 +1,73 @@
//! # `DBus` interface proxy for: `org.asuslinux.Daemon`
//!
//! This code was generated by `zbus-xmlgen` `1.0.0` from `DBus` introspection
//! data. Source: `Interface '/org/asuslinux/Anime' from service
//! 'org.asuslinux.Daemon' on session bus`.
//!
//! You may prefer to adapt it, instead of using it verbatim.
//!
//! More information can be found in the
//! [Writing a client proxy](https://dbus.pages.freedesktop.org/zbus/client.html)
//! section of the zbus documentation.
//!
//! This `DBus` object implements
//! [standard `DBus` interfaces](https://dbus.freedesktop.org/doc/dbus-specification.html),
//! (`org.freedesktop.DBus.*`) for which the following zbus proxies can be used:
//!
//! * [`zbus::fdo::PeerProxy`]
//! * [`zbus::fdo::IntrospectableProxy`]
//! * [`zbus::fdo::PropertiesProxy`]
//!
//! …consequently `zbus-xmlgen` did not generate code for the above interfaces.
#![allow(clippy::too_many_arguments)]
use zbus::proxy;
#[proxy(
interface = "org.asuslinux.Daemon",
default_path = "/org/asuslinux/Anime"
)]
trait Daemon {
/// InsertAsusGif method
fn insert_asus_gif(
&self,
index: u32,
file: &str,
time: u32,
count: u32,
brightness: f64,
) -> zbus::Result<String>;
/// InsertImage method
fn insert_image(
&self,
index: u32,
file: &str,
scale: f64,
angle: f64,
xy: &(f64, f64),
brightness: f64,
) -> zbus::Result<String>;
/// InsertImageGif method
fn insert_image_gif(
&self,
index: u32,
file: &str,
scale: f64,
angle: f64,
xy: &(f64, f64),
time: u32,
count: u32,
brightness: f64,
) -> zbus::Result<String>;
/// InsertPause method
fn insert_pause(&self, index: u32, millis: u64) -> zbus::Result<String>;
/// RemoveItem method
fn remove_item(&self, index: u32) -> zbus::Result<String>;
/// SetState method
fn set_state(&self, on: bool) -> zbus::Result<()>;
}

49
asusd/Cargo.toml Normal file
View File

@@ -0,0 +1,49 @@
[package]
name = "asusd"
license.workspace = true
version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
description.workspace = true
edition.workspace = true
[[bin]]
name = "asusd"
path = "src/daemon.rs"
[dependencies]
config-traits = { path = "../config-traits" }
rog_anime = { path = "../rog-anime", features = ["dbus"] }
rog_slash = { path = "../rog-slash", features = ["dbus"] }
rog_aura = { path = "../rog-aura", features = ["dbus"] }
rog_platform = { path = "../rog-platform" }
rog_profiles = { path = "../rog-profiles" }
dmi_id = { path = "../dmi-id" }
futures-lite = "*"
udev.workspace = true
inotify.workspace = true
mio.workspace = true
tokio.workspace = true
# console-subscriber = "0.2.0"
# cli and logging
log.workspace = true
env_logger.workspace = true
zbus.workspace = true
logind-zbus.workspace = true
# serialisation
serde.workspace = true
serde_derive.workspace = true
concat-idents.workspace = true
[dev-dependencies]
cargo-husky.workspace = true
[package.metadata.cargo-machete]
ignored = ["serde"]

159
asusd/src/config.rs Normal file
View File

@@ -0,0 +1,159 @@
use config_traits::{StdConfig, StdConfigLoad1};
use rog_platform::cpu::CPUEPP;
use rog_platform::platform::ThrottlePolicy;
use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "asusd.ron";
#[derive(Deserialize, Serialize, Debug, PartialEq, PartialOrd)]
pub struct Config {
/// Save charge limit for restoring on boot/resume
pub 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,
/// Which throttle/profile to use on AC power
pub throttle_policy_on_ac: ThrottlePolicy,
/// 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
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ppt_pl1_spl: Option<u8>,
/// Defaults to `None` if not supported
#[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>,
/// Temporary state for AC/Batt
#[serde(skip)]
pub last_power_plugged: u8,
}
impl Default for Config {
fn default() -> Self {
Self {
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,
throttle_policy_on_ac: ThrottlePolicy::Performance,
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(),
last_power_plugged: Default::default(),
}
}
}
impl StdConfig for Config {
fn new() -> Self {
Config {
charge_control_end_threshold: 100,
disable_nvidia_powerd_on_battery: true,
throttle_policy_on_battery: ThrottlePolicy::Quiet,
throttle_policy_on_ac: ThrottlePolicy::Performance,
ac_command: String::new(),
bat_command: String::new(),
..Default::default()
}
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
impl StdConfigLoad1<Config507> for Config {}
#[derive(Deserialize, Serialize)]
pub struct Config507 {
/// Save charge limit for restoring on boot
pub charge_control_end_threshold: u8,
pub panel_od: 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 ppt_pl1_spl: Option<u8>,
pub ppt_pl2_sppt: Option<u8>,
pub ppt_fppt: Option<u8>,
pub ppt_apu_sppt: Option<u8>,
pub ppt_platform_sppt: Option<u8>,
pub nv_dynamic_boost: Option<u8>,
pub nv_temp_target: Option<u8>,
}
impl From<Config507> for Config {
fn from(c: Config507) -> Self {
Self {
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,
throttle_policy_on_ac: c.platform_policy_on_ac,
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,
}
}
}

View File

@@ -0,0 +1,229 @@
use std::time::Duration;
use config_traits::{StdConfig, StdConfigLoad2};
use rog_anime::error::AnimeError;
use rog_anime::usb::Brightness;
use rog_anime::{
ActionData, ActionLoader, AnimTime, Animations, AnimeType, DeviceState, Fade, Vec2,
};
use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "anime.ron";
#[derive(Deserialize, Serialize)]
pub struct AnimeConfigV460 {
pub system: Vec<ActionLoader>,
pub boot: Vec<ActionLoader>,
pub wake: Vec<ActionLoader>,
pub sleep: Vec<ActionLoader>,
pub shutdown: Vec<ActionLoader>,
pub brightness: f32,
}
impl From<AnimeConfigV460> for AnimeConfig {
fn from(c: AnimeConfigV460) -> AnimeConfig {
AnimeConfig {
system: c.system,
boot: c.boot,
wake: c.wake,
shutdown: c.shutdown,
..Default::default()
}
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct AnimeConfigV472 {
pub model_override: Option<AnimeType>,
pub system: Vec<ActionLoader>,
pub boot: Vec<ActionLoader>,
pub wake: Vec<ActionLoader>,
pub sleep: Vec<ActionLoader>,
pub shutdown: Vec<ActionLoader>,
pub brightness: f32,
pub display_enabled: bool,
pub display_brightness: Brightness,
pub builtin_anims_enabled: bool,
pub builtin_anims: Animations,
}
impl From<AnimeConfigV472> for AnimeConfig {
fn from(c: AnimeConfigV472) -> AnimeConfig {
AnimeConfig {
system: c.system,
boot: c.boot,
wake: c.wake,
shutdown: c.shutdown,
model_override: c.model_override,
display_enabled: c.display_enabled,
display_brightness: c.display_brightness,
builtin_anims_enabled: c.builtin_anims_enabled,
builtin_anims: c.builtin_anims,
..Default::default()
}
}
}
#[derive(Deserialize, Serialize, Default)]
pub struct AnimeConfigCached {
pub system: Vec<ActionData>,
pub boot: Vec<ActionData>,
pub wake: Vec<ActionData>,
pub shutdown: Vec<ActionData>,
}
impl AnimeConfigCached {
pub fn init_from_config(
&mut self,
config: &AnimeConfig,
anime_type: AnimeType,
) -> Result<(), AnimeError> {
let mut sys = Vec::with_capacity(config.system.len());
for ani in &config.system {
sys.push(ActionData::from_anime_action(anime_type, ani)?);
}
self.system = sys;
let mut boot = Vec::with_capacity(config.boot.len());
for ani in &config.boot {
boot.push(ActionData::from_anime_action(anime_type, ani)?);
}
self.boot = boot;
let mut wake = Vec::with_capacity(config.wake.len());
for ani in &config.wake {
wake.push(ActionData::from_anime_action(anime_type, ani)?);
}
self.wake = wake;
let mut shutdown = Vec::with_capacity(config.shutdown.len());
for ani in &config.shutdown {
shutdown.push(ActionData::from_anime_action(anime_type, ani)?);
}
self.shutdown = shutdown;
Ok(())
}
}
/// Config for base system actions for the anime display
#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct AnimeConfig {
pub model_override: Option<AnimeType>,
pub system: Vec<ActionLoader>,
pub boot: Vec<ActionLoader>,
pub wake: Vec<ActionLoader>,
pub shutdown: Vec<ActionLoader>,
// pub brightness: f32,
pub display_enabled: bool,
pub display_brightness: Brightness,
pub builtin_anims_enabled: bool,
pub off_when_unplugged: bool,
pub off_when_suspended: bool,
pub off_when_lid_closed: bool,
pub brightness_on_battery: Brightness,
pub builtin_anims: Animations,
}
impl Default for AnimeConfig {
fn default() -> Self {
AnimeConfig {
model_override: None,
system: Vec::new(),
boot: Vec::new(),
wake: Vec::new(),
shutdown: Vec::new(),
// brightness: 1.0,
display_enabled: true,
display_brightness: Brightness::Med,
builtin_anims_enabled: true,
off_when_unplugged: true,
off_when_suspended: true,
off_when_lid_closed: true,
brightness_on_battery: Brightness::Low,
builtin_anims: Animations::default(),
}
}
}
impl StdConfig for AnimeConfig {
fn new() -> Self {
Self::create_default()
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
impl StdConfigLoad2<AnimeConfigV460, AnimeConfigV472> for AnimeConfig {}
impl From<&AnimeConfig> for DeviceState {
fn from(config: &AnimeConfig) -> Self {
DeviceState {
display_enabled: config.display_enabled,
display_brightness: config.display_brightness,
builtin_anims_enabled: config.builtin_anims_enabled,
builtin_anims: config.builtin_anims,
off_when_unplugged: config.off_when_unplugged,
off_when_suspended: config.off_when_suspended,
off_when_lid_closed: config.off_when_lid_closed,
brightness_on_battery: config.brightness_on_battery,
}
}
}
impl AnimeConfig {
// fn clamp_config_brightness(mut config: &mut AnimeConfig) {
// if config.brightness < 0.0 || config.brightness > 1.0 {
// warn!(
// "Clamped brightness to [0.0 ; 1.0], was {}",
// config.brightness
// );
// config.brightness = f32::max(0.0, f32::min(1.0, config.brightness));
// }
// }
fn create_default() -> Self {
// 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,
}],
..Default::default()
}
}
}

292
asusd/src/ctrl_anime/mod.rs Normal file
View File

@@ -0,0 +1,292 @@
pub mod config;
/// Implements `CtrlTask`, Reloadable, `ZbusRun`
pub mod trait_impls;
use std::convert::TryFrom;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread::sleep;
use ::zbus::export::futures_util::lock::Mutex;
use config_traits::{StdConfig, StdConfigLoad2};
use log::{error, info, warn};
use rog_anime::error::AnimeError;
use rog_anime::usb::{
get_anime_type, pkt_flush, pkt_set_brightness, pkt_set_enable_display,
pkt_set_enable_powersave_anim, pkts_for_init, Brightness,
};
use rog_anime::{ActionData, AnimeDataBuffer, AnimePacketType, AnimeType};
use rog_platform::hid_raw::HidRaw;
use rog_platform::usb_raw::USBRaw;
use self::config::{AnimeConfig, AnimeConfigCached};
use crate::error::RogError;
enum Node {
Usb(USBRaw),
Hid(HidRaw),
}
impl Node {
pub fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
// TODO: map and pass on errors
match self {
Node::Usb(u) => {
u.write_bytes(message).ok();
}
Node::Hid(h) => {
h.write_bytes(message).ok();
}
}
Ok(())
}
pub fn set_builtins_enabled(&self, enabled: bool, bright: Brightness) -> Result<(), RogError> {
self.write_bytes(&pkt_set_enable_powersave_anim(enabled))?;
self.write_bytes(&pkt_set_enable_display(enabled))?;
self.write_bytes(&pkt_set_brightness(bright))?;
self.write_bytes(&pkt_set_enable_powersave_anim(enabled))
}
}
pub struct CtrlAnime {
// node: HidRaw,
node: Node,
anime_type: AnimeType,
cache: AnimeConfigCached,
config: AnimeConfig,
// set to force thread to exit
thread_exit: Arc<AtomicBool>,
// Set to false when the thread exits
thread_running: Arc<AtomicBool>,
}
impl CtrlAnime {
#[inline]
pub fn new() -> Result<CtrlAnime, RogError> {
let usb = USBRaw::new(0x193b).ok();
let hid = HidRaw::new("193b").ok();
let node = if usb.is_some() {
info!("Anime using the USB interface");
unsafe { Node::Usb(usb.unwrap_unchecked()) }
} else if hid.is_some() {
info!("Anime using the HID interface");
unsafe { Node::Hid(hid.unwrap_unchecked()) }
} else {
return Err(RogError::Anime(AnimeError::NoDevice));
};
// TODO: something better to set wakeups disabled
// if matches!(node, Node::Usb(_)) {
// if let Ok(mut enumerator) = udev::Enumerator::new() {
// enumerator.match_subsystem("usb").ok();
// enumerator.match_attribute("idProduct", "193b").ok();
// if let Ok(mut enumer) = enumerator.scan_devices() {
// if let Some(mut dev) = enumer.next() {
// dev.set_attribute_value("power/wakeup", "disabled").ok();
// }
// }
// }
// }
let config = AnimeConfig::new().load();
let mut anime_type = get_anime_type()?;
if let AnimeType::Unknown = anime_type {
if let Some(model) = config.model_override {
warn!("Overriding the Animatrix type as {model:?}");
anime_type = model;
}
}
info!("Device has an AniMe Matrix display: {anime_type:?}");
let mut cache = AnimeConfigCached::default();
cache.init_from_config(&config, anime_type)?;
let ctrl = CtrlAnime {
node,
anime_type,
cache,
config,
thread_exit: Arc::new(AtomicBool::new(false)),
thread_running: Arc::new(AtomicBool::new(false)),
};
ctrl.do_initialization()?;
Ok(ctrl)
}
// let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
/// Start an action thread. This is classed as a singleton and there should
/// be only one running - so the thread uses atomics to signal run/exit.
///
/// Because this also writes to the usb device, other write tries (display
/// only) *must* get the mutex lock and set the `thread_exit` atomic.
async fn run_thread(inner: Arc<Mutex<CtrlAnime>>, actions: Vec<ActionData>, mut once: bool) {
if actions.is_empty() {
warn!("AniMe system actions was empty");
return;
}
if let Some(lock) = inner.try_lock() {
lock.node
.write_bytes(&pkt_set_enable_powersave_anim(false))
.map_err(|err| {
warn!("rog_anime::run_animation:callback {}", err);
})
.ok();
}
// Loop rules:
// - Lock the mutex **only when required**. That is, the lock must be held for
// the shortest duration possible.
// - An AtomicBool used for thread exit should be checked in every loop,
// including nested
// The only reason for this outer thread is to prevent blocking while waiting
// for the next spawned thread to exit
// TODO: turn this in to async task (maybe? COuld still risk blocking main
// thread)
std::thread::Builder::new()
.name("AniMe system thread start".into())
.spawn(move || {
info!("AniMe new system thread started");
// Getting copies of these Atomics is done *in* the thread to ensure
// we don't block other threads/main
let thread_exit;
let thread_running;
let anime_type;
loop {
if let Some(lock) = inner.try_lock() {
thread_exit = lock.thread_exit.clone();
thread_running = lock.thread_running.clone();
anime_type = lock.anime_type;
break;
}
}
// First two loops are to ensure we *do* aquire a lock on the mutex
// The reason the loop is required is because the USB writes can block
// for up to 10ms. We can't fail to get the atomics.
while thread_running.load(Ordering::SeqCst) {
// Make any running loop exit first
thread_exit.store(true, Ordering::SeqCst);
}
info!("AniMe no previous system thread running (now)");
thread_exit.store(false, Ordering::SeqCst);
thread_running.store(true, Ordering::SeqCst);
'main: loop {
for action in &actions {
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
match action {
ActionData::Animation(frames) => {
rog_anime::run_animation(frames, &|frame| {
if thread_exit.load(Ordering::Acquire) {
info!("rog-anime: animation sub-loop was asked to exit");
return Ok(true); // Do safe exit
}
inner
.try_lock()
.map(|lock| {
lock.write_data_buffer(frame)
.map_err(|err| {
warn!(
"rog_anime::run_animation:callback {}",
err
);
})
.ok();
false // Don't exit yet
})
.map_or_else(
|| {
warn!("rog_anime::run_animation:callback failed");
Err(AnimeError::NoFrames)
},
Ok,
)
});
if thread_exit.load(Ordering::Acquire) {
info!("rog-anime: sub-loop exited and main loop exiting now");
break 'main;
}
}
ActionData::Image(image) => {
once = false;
if let Some(lock) = inner.try_lock() {
lock.write_data_buffer(image.as_ref().clone())
.map_err(|e| error!("{}", e))
.ok();
}
}
ActionData::Pause(duration) => sleep(*duration),
ActionData::AudioEq
| ActionData::SystemInfo
| ActionData::TimeDate
| ActionData::Matrix => {}
}
}
if thread_exit.load(Ordering::SeqCst) {
break 'main;
}
if once || actions.is_empty() {
break 'main;
}
}
// Clear the display on exit
if let Some(lock) = inner.try_lock() {
if let Ok(data) =
AnimeDataBuffer::from_vec(anime_type, vec![0u8; anime_type.data_length()])
.map_err(|e| error!("{}", e))
{
lock.write_data_buffer(data)
.map_err(|err| {
warn!("rog_anime::run_animation:callback {}", err);
})
.ok();
}
lock.node
.write_bytes(&pkt_set_enable_powersave_anim(
lock.config.builtin_anims_enabled,
))
.map_err(|err| {
warn!("rog_anime::run_animation:callback {}", err);
})
.ok();
}
// Loop ended, set the atmonics
thread_running.store(false, Ordering::SeqCst);
info!("AniMe system thread exited");
})
.map(|err| info!("AniMe system thread: {:?}", err))
.ok();
}
/// Write only a data packet. This will modify the leds brightness using the
/// global brightness set in config.
fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) -> Result<(), RogError> {
for led in buffer.data_mut().iter_mut() {
let mut bright = *led as f32;
if bright > 254.0 {
bright = 254.0;
}
*led = bright as u8;
}
let data = AnimePacketType::try_from(buffer)?;
for row in &data {
self.node.write_bytes(row)?;
}
self.node.write_bytes(&pkt_flush())?;
Ok(())
}
fn do_initialization(&self) -> Result<(), RogError> {
let pkts = pkts_for_init();
self.node.write_bytes(&pkts[0])?;
self.node.write_bytes(&pkts[1])?;
Ok(())
}
}

View File

@@ -0,0 +1,522 @@
use std::sync::atomic::Ordering;
use std::sync::Arc;
use config_traits::StdConfig;
use log::warn;
use logind_zbus::manager::ManagerProxy;
use rog_anime::usb::{
pkt_set_brightness, pkt_set_builtin_animations, pkt_set_enable_display,
pkt_set_enable_powersave_anim, Brightness,
};
use rog_anime::{Animations, AnimeDataBuffer, DeviceState};
use zbus::export::futures_util::lock::Mutex;
use zbus::{interface, CacheProperties, Connection, SignalContext};
use super::config::AnimeConfig;
use super::CtrlAnime;
use crate::error::RogError;
pub const ANIME_ZBUS_NAME: &str = "Anime";
pub const ANIME_ZBUS_PATH: &str = "/org/asuslinux";
async fn get_logind_manager<'a>() -> ManagerProxy<'a> {
let connection = Connection::system()
.await
.expect("Controller could not create dbus connection");
ManagerProxy::builder(&connection)
.cache_properties(CacheProperties::No)
.build()
.await
.expect("Controller could not create ManagerProxy")
}
#[derive(Clone)]
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
/// The struct with the main dbus methods requires this trait
impl crate::ZbusRun for CtrlAnimeZbus {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, ANIME_ZBUS_PATH, server).await;
}
}
// None of these calls can be guarnateed to succeed unless we loop until okay
// If the try_lock *does* succeed then any other thread trying to lock will not
// grab it until we finish.
#[interface(name = "org.asuslinux.Anime")]
impl CtrlAnimeZbus {
/// Writes a data stream of length. Will force system thread to exit until
/// it is restarted
async fn write(&self, input: AnimeDataBuffer) -> zbus::fdo::Result<()> {
self.0
.lock()
.await
.thread_exit
.store(true, Ordering::SeqCst);
self.0
.lock()
.await
.write_data_buffer(input)
.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
err
})?;
Ok(())
}
/// Set base brightness level
#[zbus(property)]
async fn brightness(&self) -> Brightness {
self.0.lock().await.config.display_brightness
}
/// Set base brightness level
#[zbus(property)]
async fn set_brightness(&self, brightness: Brightness) {
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_brightness(brightness))
.map_err(|err| {
warn!("ctrl_anime::set_brightness {}", err);
})
.ok();
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(brightness != Brightness::Off))
.map_err(|err| {
warn!("ctrl_anime::set_brightness {}", err);
})
.ok();
self.0.lock().await.config.display_enabled = brightness != Brightness::Off;
self.0.lock().await.config.display_brightness = brightness;
self.0.lock().await.config.write();
}
#[zbus(property)]
async fn builtins_enabled(&self) -> bool {
let lock = self.0.lock().await;
lock.config.builtin_anims_enabled
}
/// Enable the builtin animations or not. This is quivalent to "Powersave
/// animations" in Armory crate
#[zbus(property)]
async fn set_builtins_enabled(&self, enabled: bool) {
let brightness = self.0.lock().await.config.display_brightness;
self.0
.lock()
.await
.node
.set_builtins_enabled(enabled, brightness)
.map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err);
})
.ok();
if !enabled {
let anime_type = self.0.lock().await.anime_type;
let data = vec![255u8; anime_type.data_length()];
if let Ok(tmp) = AnimeDataBuffer::from_vec(anime_type, data).map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err);
}) {
self.0
.lock()
.await
.node
.write_bytes(tmp.data())
.map_err(|err| {
warn!("ctrl_anime::set_builtins_enabled {}", err);
})
.ok();
}
}
self.0.lock().await.config.builtin_anims_enabled = enabled;
self.0.lock().await.config.write();
if enabled {
self.0
.lock()
.await
.thread_exit
.store(true, Ordering::Release);
}
}
#[zbus(property)]
async fn builtin_animations(&self) -> Animations {
self.0.lock().await.config.builtin_anims
}
/// Set which builtin animation is used for each stage
#[zbus(property)]
async fn set_builtin_animations(&self, settings: Animations) {
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_builtin_animations(
settings.boot,
settings.awake,
settings.sleep,
settings.shutdown,
))
.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
})
.ok();
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(true))
.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
})
.ok();
self.0.lock().await.config.display_enabled = true;
self.0.lock().await.config.builtin_anims = settings;
self.0.lock().await.config.write();
}
#[zbus(property)]
async fn enable_display(&self) -> bool {
self.0.lock().await.config.display_enabled
}
/// Set whether the AniMe is enabled at all
#[zbus(property)]
async fn set_enable_display(&self, enabled: bool) {
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(enabled))
.map_err(|err| {
warn!("ctrl_anime::run_animation:callback {}", err);
})
.ok();
self.0.lock().await.config.display_enabled = enabled;
self.0.lock().await.config.write();
}
#[zbus(property)]
async fn off_when_unplugged(&self) -> bool {
self.0.lock().await.config.off_when_unplugged
}
/// Set if to turn the AniMe Matrix off when external power is unplugged
#[zbus(property)]
async fn set_off_when_unplugged(&self, enabled: bool) {
let manager = get_logind_manager().await;
let pow = manager.on_external_power().await.unwrap_or_default();
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(!pow && !enabled))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
})
.ok();
self.0.lock().await.config.off_when_unplugged = enabled;
self.0.lock().await.config.write();
}
#[zbus(property)]
async fn off_when_suspended(&self) -> bool {
self.0.lock().await.config.off_when_suspended
}
/// Set if to turn the AniMe Matrix off when the laptop is suspended
#[zbus(property)]
async fn set_off_when_suspended(&self, enabled: bool) {
self.0.lock().await.config.off_when_suspended = enabled;
self.0.lock().await.config.write();
}
#[zbus(property)]
async fn off_when_lid_closed(&self) -> bool {
self.0.lock().await.config.off_when_lid_closed
}
/// Set if to turn the AniMe Matrix off when the lid is closed
#[zbus(property)]
async fn set_off_when_lid_closed(&self, enabled: bool) {
let manager = get_logind_manager().await;
let lid = manager.lid_closed().await.unwrap_or_default();
self.0
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(lid && !enabled))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
})
.ok();
self.0.lock().await.config.off_when_lid_closed = enabled;
self.0.lock().await.config.write();
}
/// The main loop is the base system set action if the user isn't running
/// the user daemon
async fn run_main_loop(&self, start: bool) {
if start {
self.0
.lock()
.await
.thread_exit
.store(true, Ordering::SeqCst);
CtrlAnime::run_thread(
self.0.clone(),
self.0.lock().await.cache.system.clone(),
false,
)
.await;
}
}
/// Get the device state as stored by asusd
// #[zbus(property)]
async fn device_state(&self) -> DeviceState {
DeviceState::from(&self.0.lock().await.config)
}
}
impl crate::CtrlTask for CtrlAnimeZbus {
fn zbus_path() -> &'static str {
ANIME_ZBUS_PATH
}
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let inner1 = self.0.clone();
let inner2 = self.0.clone();
let inner3 = self.0.clone();
let inner4 = self.0.clone();
self.create_sys_event_tasks(
move |sleeping| {
// on_sleep
let inner = inner1.clone();
async move {
let config = inner.lock().await.config.clone();
if config.display_enabled {
inner
.lock()
.await
.thread_exit
.store(true, Ordering::Release); // ensure clean slate
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(
!(sleeping && config.off_when_suspended),
))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
if config.builtin_anims_enabled {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(
!(sleeping && config.off_when_suspended),
))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
} else if !sleeping && !config.builtin_anims_enabled {
// Run custom wake animation
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(false))
.ok(); // ensure builtins are disabled
CtrlAnime::run_thread(
inner.clone(),
inner.lock().await.cache.wake.clone(),
true,
)
.await;
}
}
}
},
move |shutting_down| {
// on_shutdown
let inner = inner2.clone();
async move {
let AnimeConfig {
display_enabled,
builtin_anims_enabled,
..
} = inner.lock().await.config;
if display_enabled && !builtin_anims_enabled {
if shutting_down {
CtrlAnime::run_thread(
inner.clone(),
inner.lock().await.cache.shutdown.clone(),
true,
)
.await;
} else {
CtrlAnime::run_thread(
inner.clone(),
inner.lock().await.cache.boot.clone(),
true,
)
.await;
}
}
}
},
move |lid_closed| {
let inner = inner3.clone();
// on lid change
async move {
let AnimeConfig {
off_when_lid_closed,
builtin_anims_enabled,
..
} = inner.lock().await.config;
if off_when_lid_closed {
if builtin_anims_enabled {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(!lid_closed))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
}
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(!lid_closed))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_lid_closed {}", err);
})
.ok();
}
}
},
move |power_plugged| {
let inner = inner4.clone();
// on power change
async move {
let AnimeConfig {
off_when_unplugged,
builtin_anims_enabled,
brightness_on_battery,
..
} = inner.lock().await.config;
if off_when_unplugged {
if builtin_anims_enabled {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_powersave_anim(power_plugged))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_suspended {}", err);
})
.ok();
}
inner
.lock()
.await
.node
.write_bytes(&pkt_set_enable_display(power_plugged))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_unplugged {}", err);
})
.ok();
} else {
inner
.lock()
.await
.node
.write_bytes(&pkt_set_brightness(brightness_on_battery))
.map_err(|err| {
warn!("create_sys_event_tasks::off_when_unplugged {}", err);
})
.ok();
}
}
},
)
.await;
Ok(())
}
}
impl crate::Reloadable for CtrlAnimeZbus {
async fn reload(&mut self) -> Result<(), RogError> {
if let Some(lock) = self.0.try_lock() {
let anim = &lock.config.builtin_anims;
// Set builtins
if lock.config.builtin_anims_enabled {
lock.node.write_bytes(&pkt_set_builtin_animations(
anim.boot,
anim.awake,
anim.sleep,
anim.shutdown,
))?;
}
// Builtins enabled or na?
lock.node.set_builtins_enabled(
lock.config.builtin_anims_enabled,
lock.config.display_brightness,
)?;
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 && lock.config.off_when_lid_closed)
|| (!power_plugged && lock.config.off_when_unplugged);
lock.node
.write_bytes(&pkt_set_enable_display(!turn_off))
.map_err(|err| {
warn!("create_sys_event_tasks::reload {}", err);
})
.ok();
if turn_off || !lock.config.display_enabled {
lock.node.write_bytes(&pkt_set_enable_display(false))?;
// early return so we don't run animation thread
return Ok(());
}
if !lock.config.builtin_anims_enabled && !lock.cache.boot.is_empty() {
lock.node
.write_bytes(&pkt_set_enable_powersave_anim(false))
.ok();
let action = lock.cache.boot.clone();
CtrlAnime::run_thread(self.0.clone(), action, true).await;
}
}
Ok(())
}
}

View File

@@ -0,0 +1,277 @@
use std::collections::BTreeMap;
use config_traits::{StdConfig, StdConfigLoad};
use log::{debug, info, warn};
use rog_aura::aura_detection::LedSupportData;
use rog_aura::keyboard::LaptopAuraPower;
use rog_aura::{
AuraDeviceType, AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT,
};
use serde_derive::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Default, Debug, Clone)]
// #[serde(default)]
pub struct AuraConfig {
pub config_name: String,
pub brightness: LedBrightness,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub multizone: Option<BTreeMap<AuraModeNum, Vec<AuraEffect>>>,
pub multizone_on: bool,
pub enabled: LaptopAuraPower,
}
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");
}
fn file_name(&self) -> String {
if self.config_name.is_empty() {
panic!("Config file name should not be empty");
}
self.config_name.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
impl StdConfigLoad for AuraConfig {}
impl AuraConfig {
/// Detect the keyboard type and load from default DB if data available
pub fn new(prod_id: &str) -> Self {
info!("Setting up AuraConfig for {prod_id:?}");
// create a default config here
let device_type = AuraDeviceType::from(prod_id);
if device_type == AuraDeviceType::Unknown {
warn!("idProduct:{prod_id:?} is unknown");
}
let support_data = LedSupportData::get_data(prod_id);
let enabled = LaptopAuraPower::new(device_type, &support_data);
let mut config = AuraConfig {
config_name: format!("aura_{prod_id}.ron"),
brightness: LedBrightness::Med,
current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(),
multizone: None,
multizone_on: false,
enabled,
};
for n in &support_data.basic_modes {
debug!("creating default for {n}");
config
.builtins
.insert(*n, AuraEffect::default_with_mode(*n));
if !support_data.basic_zones.is_empty() {
let mut default = vec![];
for (i, tmp) in support_data.basic_zones.iter().enumerate() {
default.push(AuraEffect {
mode: *n,
zone: *tmp,
colour1: *GRADIENT.get(i).unwrap_or(&GRADIENT[0]),
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
speed: Speed::Med,
direction: Direction::Left,
});
}
if let Some(m) = config.multizone.as_mut() {
m.insert(*n, default);
} else {
let mut tmp = BTreeMap::new();
tmp.insert(*n, default);
config.multizone = Some(tmp);
}
}
}
config
}
/// Set the mode data, current mode, and if multizone enabled.
///
/// Multipurpose, will accept `AuraEffect` with zones and put in the correct
/// store.
pub fn set_builtin(&mut self, effect: AuraEffect) {
self.current_mode = effect.mode;
if effect.zone() == AuraZone::None {
self.builtins.insert(*effect.mode(), effect);
self.multizone_on = false;
} else {
if let Some(multi) = self.multizone.as_mut() {
if let Some(fx) = multi.get_mut(effect.mode()) {
for fx in fx.iter_mut() {
if fx.zone == effect.zone {
*fx = effect;
return;
}
}
fx.push(effect);
} else {
multi.insert(*effect.mode(), vec![effect]);
}
} else {
let mut tmp = BTreeMap::new();
tmp.insert(*effect.mode(), vec![effect]);
self.multizone = Some(tmp);
}
self.multizone_on = true;
}
}
pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect]> {
if let Some(multi) = &self.multizone {
return multi.get(&aura_type).map(|v| v.as_slice());
}
None
}
}
#[cfg(test)]
mod tests {
use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour};
use super::AuraConfig;
#[test]
fn set_multizone_4key_config() {
let mut config = AuraConfig::new("19b6");
let effect = AuraEffect {
colour1: Colour {
r: 0xff,
g: 0x00,
b: 0xff,
},
zone: AuraZone::Key1,
..Default::default()
};
config.set_builtin(effect);
assert!(config.multizone.is_some());
let effect = AuraEffect {
colour1: Colour {
r: 0x00,
g: 0xff,
b: 0xff,
},
zone: AuraZone::Key2,
..Default::default()
};
config.set_builtin(effect);
let effect = AuraEffect {
colour1: Colour {
r: 0xff,
g: 0xff,
b: 0x00,
},
zone: AuraZone::Key3,
..Default::default()
};
config.set_builtin(effect);
let effect = AuraEffect {
colour1: Colour {
r: 0x00,
g: 0xff,
b: 0x00,
},
zone: AuraZone::Key4,
..Default::default()
};
let effect_clone = effect.clone();
config.set_builtin(effect);
// This should replace existing
config.set_builtin(effect_clone);
let res = config.multizone.unwrap();
let sta = res.get(&AuraModeNum::Static).unwrap();
assert_eq!(sta.len(), 4);
assert_eq!(
sta[0].colour1,
Colour {
r: 0xff,
g: 0x00,
b: 0xff
}
);
assert_eq!(
sta[1].colour1,
Colour {
r: 0x00,
g: 0xff,
b: 0xff
}
);
assert_eq!(
sta[2].colour1,
Colour {
r: 0xff,
g: 0xff,
b: 0x00
}
);
assert_eq!(
sta[3].colour1,
Colour {
r: 0x00,
g: 0xff,
b: 0x00
}
);
}
#[test]
fn set_multizone_multimode_config() {
let mut config = AuraConfig::new("19b6");
let effect = AuraEffect {
zone: AuraZone::Key1,
..Default::default()
};
config.set_builtin(effect);
assert!(config.multizone.is_some());
let effect = AuraEffect {
zone: AuraZone::Key2,
mode: AuraModeNum::Breathe,
..Default::default()
};
config.set_builtin(effect);
let effect = AuraEffect {
zone: AuraZone::Key3,
mode: AuraModeNum::Comet,
..Default::default()
};
config.set_builtin(effect);
let effect = AuraEffect {
zone: AuraZone::Key4,
mode: AuraModeNum::Pulse,
..Default::default()
};
config.set_builtin(effect);
let res = config.multizone.unwrap();
let sta = res.get(&AuraModeNum::Static).unwrap();
assert_eq!(sta.len(), 1);
let sta = res.get(&AuraModeNum::Breathe).unwrap();
assert_eq!(sta.len(), 1);
let sta = res.get(&AuraModeNum::Comet).unwrap();
assert_eq!(sta.len(), 1);
let sta = res.get(&AuraModeNum::Pulse).unwrap();
assert_eq!(sta.len(), 1);
}
}

View File

@@ -0,0 +1,520 @@
use std::collections::{BTreeMap, HashSet};
use config_traits::{StdConfig, StdConfigLoad};
use dmi_id::DMIID;
use inotify::Inotify;
use log::{debug, info, warn};
use rog_aura::aura_detection::LedSupportData;
use rog_aura::keyboard::{LedUsbPackets, UsbPackets};
use rog_aura::usb::{LED_APPLY, LED_SET};
use rog_aura::{
AuraDeviceType, AuraEffect, Direction, LedBrightness, Speed, GRADIENT, LED_MSG_LEN,
};
use rog_platform::hid_raw::HidRaw;
use rog_platform::keyboard_led::KeyboardBacklight;
use zbus::zvariant::OwnedObjectPath;
use super::config::AuraConfig;
use crate::ctrl_aura::manager::{dbus_path_for_dev, dbus_path_for_tuf};
use crate::error::RogError;
#[derive(Debug)]
pub enum LEDNode {
/// Brightness and/or TUF RGB controls
KbdLed(KeyboardBacklight),
/// Raw HID handle
Rog(Option<KeyboardBacklight>, HidRaw),
}
impl LEDNode {
// TODO: move various methods upwards to this
pub fn set_brightness(&self, value: u8) -> Result<(), RogError> {
match self {
LEDNode::KbdLed(k) => k.set_brightness(value)?,
LEDNode::Rog(k, _) => {
if let Some(k) = k {
k.set_brightness(value)?
} else {
debug!("No brightness control found");
}
}
}
Ok(())
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
Ok(match self {
LEDNode::KbdLed(k) => k.get_brightness()?,
LEDNode::Rog(k, _) => {
if let Some(k) = k {
k.get_brightness()?
} else {
debug!("No brightness control found");
return Err(RogError::MissingFunction(
"No keyboard brightness control found".to_string(),
));
}
}
})
}
pub fn monitor_brightness(&self) -> Result<Inotify, RogError> {
Ok(match self {
LEDNode::KbdLed(k) => k.monitor_brightness()?,
LEDNode::Rog(k, _) => {
if let Some(k) = k {
k.monitor_brightness()?
} else {
debug!("No brightness control found");
return Err(RogError::MissingFunction(
"No keyboard brightness control found".to_string(),
));
}
}
})
}
pub fn has_brightness_control(&self) -> bool {
match self {
LEDNode::KbdLed(k) => k.has_brightness(),
LEDNode::Rog(k, _) => {
if let Some(k) = k {
k.has_brightness()
} else {
false
}
}
}
}
}
/// Individual controller for one Aura device
pub struct CtrlKbdLed {
pub led_type: AuraDeviceType,
pub led_node: LEDNode,
pub supported_data: LedSupportData, // TODO: is storing this really required?
pub per_key_mode_active: bool,
pub config: AuraConfig,
pub dbus_path: OwnedObjectPath,
}
impl CtrlKbdLed {
pub fn find_all() -> Result<Vec<Self>, RogError> {
info!("Searching for all Aura devices");
let mut devices = Vec::new();
let mut found = HashSet::new(); // track and ensure we use only one hidraw per prod_id
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);
err
})?;
enumerator.match_subsystem("hidraw").map_err(|err| {
warn!("{}", err);
err
})?;
for end_point in enumerator.scan_devices()? {
// usb_device gives us a product and vendor ID
if let Some(usb_device) =
end_point.parent_with_subsystem_devtype("usb", "usb_device")?
{
// The asus_wmi driver latches MCU that controls the USB endpoints
if let Some(parent) = end_point.parent() {
if let Some(driver) = parent.driver() {
// There is a tree of devices added so filter by driver
if driver != "asus" {
continue;
}
} else {
continue;
}
}
// Device is something like 002, while its parent is the MCU
// Think of it like the device is an endpoint of the USB device attached
let mut prod_id = String::new();
if let Some(usb_id) = usb_device.attribute_value("idProduct") {
prod_id = usb_id.to_string_lossy().to_string();
let aura_dev = AuraDeviceType::from(prod_id.as_str());
if aura_dev == AuraDeviceType::Unknown || found.contains(&aura_dev) {
log::debug!("Unknown or invalid device: {usb_id:?}, skipping");
continue;
}
found.insert(aura_dev);
}
let dev_node = if let Some(dev_node) = usb_device.devnode() {
dev_node
} else {
debug!("Device has no devnode, skipping");
continue;
};
info!("AuraControl found device at: {:?}", dev_node);
let dbus_path = dbus_path_for_dev(&usb_device).unwrap_or_default();
let dev = HidRaw::from_device(end_point)?;
let mut dev = Self::from_hidraw(dev, dbus_path)?;
dev.config = Self::init_config(&prod_id);
devices.push(dev);
}
}
// Check for a TUF laptop LED. Assume there is only ever one.
if let Ok(kbd_backlight) = KeyboardBacklight::new() {
if kbd_backlight.has_kbd_rgb_mode() {
// Extra sure double-check that this isn't a laptop with crap
// ACPI with borked return on the TUF rgb methods
let dmi = DMIID::new().unwrap_or_default();
info!("Found a TUF with product family: {}", dmi.product_family);
info!("and board name: {}", dmi.board_name);
if dmi.product_family.contains("TUF") {
info!("AuraControl found a TUF laptop keyboard");
let ctrl = CtrlKbdLed {
led_type: AuraDeviceType::LaptopTuf,
led_node: LEDNode::KbdLed(kbd_backlight),
supported_data: LedSupportData::get_data("tuf"),
per_key_mode_active: false,
config: Self::init_config("tuf"),
dbus_path: dbus_path_for_tuf(),
};
devices.push(ctrl);
}
}
} else {
let dmi = DMIID::new().unwrap_or_default();
warn!("No asus::kbd_backlight found for {} ??", dmi.product_family);
}
info!("Found {} Aura devices", devices.len());
Ok(devices)
}
/// The generated data from this function has a default config. This config
/// should be overwritten. The reason for the default config is because
/// of async issues between this and udev/hidraw
pub fn from_hidraw(device: HidRaw, dbus_path: OwnedObjectPath) -> Result<Self, RogError> {
let rgb_led = KeyboardBacklight::new()
.map_err(|e| {
log::error!(
"{} is missing a keyboard backlight brightness control: {e:?}",
device.prod_id()
);
})
.ok();
let prod_id = AuraDeviceType::from(device.prod_id());
if prod_id == AuraDeviceType::Unknown {
log::error!("{} is AuraDevice::Unknown", device.prod_id());
return Err(RogError::NoAuraNode);
}
// New loads data from the DB also
// let config = Self::init_config(prod_id, data);
let data = LedSupportData::get_data(device.prod_id());
let ctrl = CtrlKbdLed {
led_type: prod_id,
led_node: LEDNode::Rog(rgb_led, device),
supported_data: data.clone(),
per_key_mode_active: false,
config: AuraConfig::default(),
dbus_path,
};
Ok(ctrl)
}
pub fn init_config(prod_id: &str) -> AuraConfig {
// New loads data from the DB also
let mut config_init = AuraConfig::new(prod_id);
// config_init.set_filename(prod_id);
let mut config_loaded = config_init.clone().load();
// update the initialised data with what we loaded from disk
for mode in &mut config_init.builtins {
// update init values from loaded values if they exist
if let Some(loaded) = config_loaded.builtins.get(mode.0) {
*mode.1 = loaded.clone();
}
}
// Then replace just incase the initialised data contains new modes added
config_loaded.builtins = config_init.builtins;
if let (Some(mut multizone_init), Some(multizone_loaded)) =
(config_init.multizone, config_loaded.multizone.as_mut())
{
for mode in multizone_init.iter_mut() {
// update init values from loaded values if they exist
if let Some(loaded) = multizone_loaded.get(mode.0) {
let mut new_set = Vec::new();
let data = LedSupportData::get_data(prod_id);
// only reuse a zone mode if the mode is supported
for mode in loaded {
if data.basic_modes.contains(&mode.mode) {
new_set.push(mode.clone());
}
}
*mode.1 = new_set;
}
}
*multizone_loaded = multizone_init;
}
config_loaded
}
/// Set combination state for boot animation/sleep animation/all leds/keys
/// leds/side leds LED active
pub(super) fn set_power_states(&mut self) -> Result<(), RogError> {
if let LEDNode::KbdLed(_platform) = &mut self.led_node {
// TODO: tuf bool array
// if let Some(pwr) =
// AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) {
// let buf = [1, pwr[1] as u8, pwr[2] as u8, pwr[3] as u8,
// pwr[4] as u8]; platform.set_kbd_rgb_state(&buf)?;
// }
} else if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let bytes = self.config.enabled.to_bytes(self.led_type);
let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2], bytes[3]];
hid_raw.write_bytes(&message)?;
hid_raw.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
hid_raw.write_bytes(&LED_APPLY)?;
}
Ok(())
}
/// Write an effect block. This is for per-key, but can be repurposed to
/// write the raw factory mode packets - when doing this it is expected that
/// only the first `Vec` (`effect[0]`) is valid.
pub fn write_effect_block(&mut self, effect: &UsbPackets) -> Result<(), RogError> {
if self.config.brightness == LedBrightness::Off {
self.config.brightness = LedBrightness::Med;
self.config.write();
}
let pkt_type = effect[0][1];
const PER_KEY_TYPE: u8 = 0xbc;
if pkt_type != PER_KEY_TYPE {
self.per_key_mode_active = false;
if let LEDNode::Rog(_, hid_raw) = &self.led_node {
hid_raw.write_bytes(&effect[0])?;
hid_raw.write_bytes(&LED_SET)?;
// hid_raw.write_bytes(&LED_APPLY)?;
}
} else {
if !self.per_key_mode_active {
if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let init = LedUsbPackets::get_init_msg();
hid_raw.write_bytes(&init)?;
}
self.per_key_mode_active = true;
}
if let LEDNode::Rog(_, hid_raw) = &self.led_node {
for row in effect.iter() {
hid_raw.write_bytes(row)?;
}
} else if let LEDNode::KbdLed(tuf) = &self.led_node {
for row in effect.iter() {
let r = row[9];
let g = row[10];
let b = row[11];
tuf.set_kbd_rgb_mode(&[0, 0, r, g, b, 0])?;
}
}
}
Ok(())
}
pub fn write_mode(&mut self, mode: &AuraEffect) -> Result<(), RogError> {
if let LEDNode::KbdLed(platform) = &self.led_node {
let buf = [
1,
mode.mode as u8,
mode.colour1.r,
mode.colour1.g,
mode.colour1.b,
mode.speed as u8,
];
platform.set_kbd_rgb_mode(&buf)?;
} else if let LEDNode::Rog(_, hid_raw) = &self.led_node {
let bytes: [u8; LED_MSG_LEN] = mode.into();
hid_raw.write_bytes(&bytes)?;
hid_raw.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
hid_raw.write_bytes(&LED_APPLY)?;
} else {
return Err(RogError::NoAuraKeyboard);
}
self.per_key_mode_active = false;
Ok(())
}
pub(super) fn write_current_config_mode(&mut self) -> Result<(), RogError> {
if self.config.multizone_on {
let mode = self.config.current_mode;
let mut create = false;
// There is no multizone config for this mode so create one here
// using the colours of rainbow if it exists, or first available
// mode, or random
if self.config.multizone.is_none() {
create = true;
} else if let Some(multizones) = self.config.multizone.as_ref() {
if !multizones.contains_key(&mode) {
create = true;
}
}
if create {
info!("No user-set config for zone founding, attempting a default");
self.create_multizone_default()?;
}
if let Some(multizones) = self.config.multizone.as_mut() {
if let Some(set) = multizones.get(&mode) {
for mode in set.clone() {
self.write_mode(&mode)?;
}
}
}
} else {
let mode = self.config.current_mode;
if let Some(effect) = self.config.builtins.get(&mode).cloned() {
self.write_mode(&effect)?;
}
}
Ok(())
}
/// Create a default for the `current_mode` if multizone and no config
/// exists.
fn create_multizone_default(&mut self) -> Result<(), RogError> {
let mut default = vec![];
for (i, tmp) in self.supported_data.basic_zones.iter().enumerate() {
default.push(AuraEffect {
mode: self.config.current_mode,
zone: *tmp,
colour1: *GRADIENT.get(i).unwrap_or(&GRADIENT[0]),
colour2: *GRADIENT.get(GRADIENT.len() - i).unwrap_or(&GRADIENT[6]),
speed: Speed::Med,
direction: Direction::Left,
});
}
if default.is_empty() {
return Err(RogError::AuraEffectNotSupported);
}
if let Some(multizones) = self.config.multizone.as_mut() {
multizones.insert(self.config.current_mode, default);
} else {
let mut tmp = BTreeMap::new();
tmp.insert(self.config.current_mode, default);
self.config.multizone = Some(tmp);
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use rog_aura::aura_detection::LedSupportData;
use rog_aura::{AuraDeviceType, AuraModeNum, AuraZone, PowerZones};
use rog_platform::hid_raw::HidRaw;
use rog_platform::keyboard_led::KeyboardBacklight;
use zbus::zvariant::OwnedObjectPath;
use super::CtrlKbdLed;
use crate::ctrl_aura::config::AuraConfig;
use crate::ctrl_aura::controller::LEDNode;
#[test]
#[ignore = "Unable to run in CI as the HIDRAW device is required"]
fn create_multizone_if_no_config() {
// Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::new("19b6");
let supported_basic_modes = LedSupportData {
device_name: String::new(),
product_id: String::new(),
layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![],
advanced_type: rog_aura::keyboard::AdvancedAuraType::None,
power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow],
};
let mut controller = CtrlKbdLed {
led_type: AuraDeviceType::LaptopPost2021,
led_node: LEDNode::Rog(
Some(KeyboardBacklight::default()),
HidRaw::new("19b6").unwrap(),
),
supported_data: supported_basic_modes,
per_key_mode_active: false,
config,
dbus_path: OwnedObjectPath::default(),
};
assert!(controller.config.multizone.is_none());
assert!(controller.create_multizone_default().is_err());
assert!(controller.config.multizone.is_none());
controller.supported_data.basic_zones.push(AuraZone::Key1);
controller.supported_data.basic_zones.push(AuraZone::Key2);
assert!(controller.create_multizone_default().is_ok());
assert!(controller.config.multizone.is_some());
let m = controller.config.multizone.unwrap();
assert!(m.contains_key(&AuraModeNum::Static));
let e = m.get(&AuraModeNum::Static).unwrap();
assert_eq!(e.len(), 2);
assert_eq!(e[0].zone, AuraZone::Key1);
assert_eq!(e[1].zone, AuraZone::Key2);
}
#[test]
#[ignore = "Unable to run in CI as the HIDRAW device is required"]
// TODO: use sim device
fn next_mode_create_multizone_if_no_config() {
// Checking to ensure set_mode errors when unsupported modes are tried
let config = AuraConfig::new("19b6");
let supported_basic_modes = LedSupportData {
device_name: String::new(),
product_id: String::new(),
layout_name: "ga401".to_owned(),
basic_modes: vec![AuraModeNum::Static],
basic_zones: vec![AuraZone::Key1, AuraZone::Key2],
advanced_type: rog_aura::keyboard::AdvancedAuraType::None,
power_zones: vec![PowerZones::Keyboard, PowerZones::RearGlow],
};
let mut controller = CtrlKbdLed {
led_type: AuraDeviceType::LaptopPost2021,
led_node: LEDNode::Rog(
Some(KeyboardBacklight::default()),
HidRaw::new("19b6").unwrap(),
),
supported_data: supported_basic_modes,
per_key_mode_active: false,
config,
dbus_path: OwnedObjectPath::default(),
};
assert!(controller.config.multizone.is_none());
controller.config.multizone_on = true;
// This is called in toggle_mode. It will error here because we have no
// keyboard node in tests.
assert_eq!(
controller
.write_current_config_mode()
.unwrap_err()
.to_string(),
"No supported Aura keyboard"
);
assert!(controller.config.multizone.is_some());
let m = controller.config.multizone.unwrap();
assert!(m.contains_key(&AuraModeNum::Static));
let e = m.get(&AuraModeNum::Static).unwrap();
assert_eq!(e.len(), 2);
assert_eq!(e[0].zone, AuraZone::Key1);
assert_eq!(e[1].zone, AuraZone::Key2);
}
}

View File

@@ -0,0 +1,187 @@
// Plan:
// - Manager has udev monitor on USB looking for ROG devices
// - If a device is found, add it to watch
// - Add it to Zbus server
// - If udev sees device removed then remove the zbus path
use std::collections::HashSet;
use log::{debug, error, info, warn};
use mio::{Events, Interest, Poll, Token};
use rog_aura::AuraDeviceType;
use rog_platform::hid_raw::HidRaw;
use tokio::task::spawn_blocking;
use udev::{Device, MonitorBuilder};
use zbus::object_server::SignalContext;
use zbus::zvariant::{ObjectPath, OwnedObjectPath};
use zbus::Connection;
use crate::ctrl_aura::controller::CtrlKbdLed;
use crate::ctrl_aura::trait_impls::{CtrlAuraZbus, AURA_ZBUS_PATH};
use crate::error::RogError;
use crate::{CtrlTask, Reloadable};
pub struct AuraManager {
_connection: Connection,
}
impl AuraManager {
pub async fn new(connection: Connection) -> Result<Self, RogError> {
let conn_copy = connection.clone();
let mut interfaces = HashSet::new();
// Do the initial keyboard detection:
let all = CtrlKbdLed::find_all()?;
for ctrl in all {
let path = ctrl.dbus_path.clone();
interfaces.insert(path.clone()); // ensure we record the initial stuff
let sig_ctx = CtrlAuraZbus::signal_context(&connection)?;
let sig_ctx2 = sig_ctx.clone();
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
start_tasks(zbus, connection.clone(), sig_ctx2, path).await?;
}
let manager = Self {
_connection: connection,
};
// detect all plugged in aura devices (eventually)
// only USB devices are detected for here
spawn_blocking(move || {
let mut monitor = MonitorBuilder::new()?.match_subsystem("hidraw")?.listen()?;
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(1024);
poll.registry()
.register(&mut monitor, Token(0), Interest::READABLE)?;
loop {
if poll.poll(&mut events, None).is_err() {
continue;
}
for event in monitor.iter() {
let parent = if let Some(parent) =
event.parent_with_subsystem_devtype("usb", "usb_device")?
{
parent
} else {
continue;
};
let action = if let Some(action) = event.action() {
action
} else {
continue;
};
let id_product = if let Some(id_product) = parent.attribute_value("idProduct") {
id_product.to_string_lossy()
} else {
continue;
};
let path = if let Some(path) = dbus_path_for_dev(&parent) {
path
} else {
continue;
};
let aura_device = AuraDeviceType::from(&*id_product);
if aura_device == AuraDeviceType::Unknown {
warn!("idProduct:{id_product:?} is unknown, not using");
continue;
}
if action == "remove" {
if interfaces.remove(&path) {
info!("AuraManager removing: {path:?}");
let conn_copy = conn_copy.clone();
tokio::spawn(async move {
let res = conn_copy
.object_server()
.remove::<CtrlAuraZbus, _>(&path)
.await
.map_err(|e| {
error!("Failed to remove {path:?}, {e:?}");
e
})?;
info!("AuraManager removed: {path:?}, {res}");
Ok::<(), RogError>(())
});
}
} else if action == "add" {
if interfaces.contains(&path) {
debug!("Already a ctrl at {path:?}");
continue;
}
// Need to check the driver is asus to prevent using hid_generic
if let Some(p2) = event.parent() {
if let Some(driver) = p2.driver() {
// There is a tree of devices added so filter by driver
if driver != "asus" {
debug!("{id_product:?} driver was not asus, skipping");
continue;
}
} else {
continue;
}
}
if let Some(dev_node) = event.devnode() {
if let Ok(raw) = HidRaw::from_device(event.device())
.map_err(|e| error!("device path error: {e:?}"))
{
if let Ok(mut ctrl) = CtrlKbdLed::from_hidraw(raw, path.clone()) {
ctrl.config = CtrlKbdLed::init_config(&id_product);
interfaces.insert(path.clone());
info!("AuraManager starting device at: {dev_node:?}, {path:?}");
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
let zbus = CtrlAuraZbus::new(ctrl, sig_ctx);
let sig_ctx = CtrlAuraZbus::signal_context(&conn_copy)?;
let conn_copy = conn_copy.clone();
tokio::spawn(async move {
start_tasks(zbus, conn_copy.clone(), sig_ctx, path).await
});
}
}
}
};
}
}
// Required for return type on spawn
#[allow(unreachable_code)]
Ok::<(), RogError>(())
});
Ok(manager)
}
}
pub(crate) fn dbus_path_for_dev(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(filename) = super::filename_partial(parent) {
return Some(
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/{filename}")).into(),
);
}
None
}
pub(crate) fn dbus_path_for_tuf() -> OwnedObjectPath {
ObjectPath::from_str_unchecked(&format!("{AURA_ZBUS_PATH}/tuf")).into()
}
async fn start_tasks(
mut zbus: CtrlAuraZbus,
connection: Connection,
_signal_ctx: SignalContext<'static>,
path: OwnedObjectPath,
) -> Result<(), RogError> {
// let task = zbus.clone();
// let signal_ctx = signal_ctx.clone();
zbus.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
connection.object_server().at(path, zbus).await.unwrap();
// TODO: skip this until we keep handles to tasks so they can be killed
// task.create_tasks(signal_ctx).await
Ok(())
}

View File

@@ -0,0 +1,29 @@
use udev::Device;
use zbus::zvariant::{ObjectPath, OwnedObjectPath};
pub mod config;
pub mod controller;
pub mod manager;
/// Implements `CtrlTask`, `Reloadable`, `ZbusRun`
pub mod trait_impls;
/// Returns only the Device details concatenated in a form usable for
/// adding/appending to a filename
pub(super) fn filename_partial(parent: &Device) -> Option<OwnedObjectPath> {
if let Some(id_product) = parent.attribute_value("idProduct") {
let id_product = id_product.to_string_lossy();
let path = if let Some(devnum) = parent.attribute_value("devnum") {
let devnum = devnum.to_string_lossy();
if let Some(devpath) = parent.attribute_value("devpath") {
let devpath = devpath.to_string_lossy();
format!("{id_product}_{devnum}_{devpath}")
} else {
format!("{id_product}_{devnum}")
}
} else {
format!("{id_product}")
};
return Some(ObjectPath::from_str_unchecked(&path).into());
}
None
}

View File

@@ -0,0 +1,303 @@
use std::collections::BTreeMap;
use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_aura::keyboard::{LaptopAuraPower, UsbPackets};
use rog_aura::{AuraDeviceType, AuraEffect, AuraModeNum, AuraZone, LedBrightness, PowerZones};
use zbus::export::futures_util::lock::{Mutex, MutexGuard};
use zbus::export::futures_util::StreamExt;
use zbus::fdo::Error as ZbErr;
use zbus::{interface, SignalContext};
use super::controller::CtrlKbdLed;
use crate::error::RogError;
use crate::CtrlTask;
pub const AURA_ZBUS_NAME: &str = "Aura";
pub const AURA_ZBUS_PATH: &str = "/org/asuslinux";
#[derive(Clone)]
pub struct CtrlAuraZbus(Arc<Mutex<CtrlKbdLed>>, SignalContext<'static>);
impl CtrlAuraZbus {
pub fn new(controller: CtrlKbdLed, signal: SignalContext<'static>) -> Self {
Self(Arc::new(Mutex::new(controller)), signal)
}
fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> {
let bright = lock.led_node.get_brightness().unwrap_or_default();
lock.config.read();
lock.config.brightness = bright.into();
lock.config.write();
Ok(())
}
}
/// The main interface for changing, reading, or notfying
///
/// LED commands are split between Brightness, Modes, Per-Key
#[interface(name = "org.asuslinux.Aura")]
impl CtrlAuraZbus {
/// Return the device type for this Aura keyboard
#[zbus(property)]
async fn device_type(&self) -> AuraDeviceType {
let ctrl = self.0.lock().await;
ctrl.led_type
}
/// Return the current LED brightness
#[zbus(property)]
async fn brightness(&self) -> Result<LedBrightness, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.led_node.get_brightness().map(|n| n.into())?)
}
/// Set the keyboard brightness level (0-3)
#[zbus(property)]
async fn set_brightness(&mut self, brightness: LedBrightness) -> Result<(), ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.led_node.set_brightness(brightness.into())?)
}
/// Total levels of brightness available
#[zbus(property)]
async fn supported_brightness(&self) -> Vec<LedBrightness> {
vec![
LedBrightness::Off,
LedBrightness::Low,
LedBrightness::Med,
LedBrightness::High,
]
}
/// The total available modes
#[zbus(property)]
async fn supported_basic_modes(&self) -> Result<Vec<AuraModeNum>, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.config.builtins.keys().cloned().collect())
}
#[zbus(property)]
async fn supported_basic_zones(&self) -> Result<Vec<AuraZone>, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.supported_data.basic_zones.clone())
}
#[zbus(property)]
async fn supported_power_zones(&self) -> Result<Vec<PowerZones>, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.supported_data.power_zones.clone())
}
/// The current mode data
#[zbus(property)]
async fn led_mode(&self) -> Result<AuraModeNum, ZbErr> {
let ctrl = self.0.lock().await;
Ok(ctrl.config.current_mode)
}
/// Set an Aura effect if the effect mode or zone is supported.
///
/// On success the aura config file is read to refresh cached values, then
/// the effect is stored and config written to disk.
#[zbus(property)]
async fn set_led_mode(&mut self, num: AuraModeNum) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await;
ctrl.config.current_mode = num;
ctrl.write_current_config_mode()?;
if ctrl.config.brightness == LedBrightness::Off {
ctrl.config.brightness = LedBrightness::Med;
}
if ctrl.led_node.has_brightness_control() {
ctrl.led_node
.set_brightness(ctrl.config.brightness.into())?;
}
ctrl.config.write();
self.led_mode_data_invalidate(&self.1).await.ok();
Ok(())
}
/// The current mode data
#[zbus(property)]
async fn led_mode_data(&self) -> Result<AuraEffect, ZbErr> {
let ctrl = self.0.lock().await;
let mode = ctrl.config.current_mode;
match ctrl.config.builtins.get(&mode) {
Some(effect) => Ok(effect.clone()),
None => Err(ZbErr::Failed("Could not get the current effect".into())),
}
}
/// Set an Aura effect if the effect mode or zone is supported.
///
/// On success the aura config file is read to refresh cached values, then
/// the effect is stored and config written to disk.
#[zbus(property)]
async fn set_led_mode_data(&mut self, effect: AuraEffect) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await;
if !ctrl.supported_data.basic_modes.contains(&effect.mode)
|| effect.zone != AuraZone::None
&& !ctrl.supported_data.basic_zones.contains(&effect.zone)
{
return Err(ZbErr::NotSupported(format!(
"The Aura effect is not supported: {effect:?}"
)));
}
ctrl.write_mode(&effect)?;
if ctrl.config.brightness == LedBrightness::Off {
ctrl.config.brightness = LedBrightness::Med;
}
if ctrl.led_node.has_brightness_control() {
ctrl.led_node
.set_brightness(ctrl.config.brightness.into())?;
}
ctrl.config.set_builtin(effect);
ctrl.config.write();
self.led_mode_invalidate(&self.1).await.ok();
Ok(())
}
/// Get the data set for every mode available
async fn all_mode_data(&self) -> BTreeMap<AuraModeNum, AuraEffect> {
let ctrl = self.0.lock().await;
ctrl.config.builtins.clone()
}
// As property doesn't work for AuraPowerDev (complexity of serialization?)
#[zbus(property)]
async fn led_power(&self) -> LaptopAuraPower {
let ctrl = self.0.lock().await;
ctrl.config.enabled.clone()
}
/// Set a variety of states, input is array of enum.
/// `enabled` sets if the sent array should be disabled or enabled
///
/// For Modern ROG devices the "enabled" flag is ignored.
#[zbus(property)]
async fn set_led_power(&mut self, options: LaptopAuraPower) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await;
for opt in options.states {
let zone = opt.zone;
for config in ctrl.config.enabled.states.iter_mut() {
if config.zone == zone {
*config = opt;
}
}
}
ctrl.config.write();
Ok(ctrl.set_power_states().map_err(|e| {
warn!("{}", e);
e
})?)
}
/// On machine that have some form of either per-key keyboard or per-zone
/// this can be used to write custom effects over dbus. The input is a
/// nested `Vec<Vec<8>>` where `Vec<u8>` is a raw USB packet
async fn direct_addressing_raw(&self, data: UsbPackets) -> Result<(), ZbErr> {
let mut ctrl = self.0.lock().await;
ctrl.write_effect_block(&data)?;
Ok(())
}
}
impl CtrlTask for CtrlAuraZbus {
fn zbus_path() -> &'static str {
"/org/asuslinux"
}
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
let load_save =
|start: bool, mut lock: MutexGuard<'_, CtrlKbdLed>| -> Result<(), RogError> {
// If waking up
if !start {
info!("CtrlKbdLedTask reloading brightness and modes");
if lock.led_node.has_brightness_control() {
lock.led_node
.set_brightness(lock.config.brightness.into())
.map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
}
lock.write_current_config_mode().map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
} else if start {
Self::update_config(&mut lock).map_err(|e| {
error!("CtrlKbdLedTask: {e}");
e
})?;
}
Ok(())
};
let inner1 = self.0.clone();
let inner3 = self.0.clone();
self.create_sys_event_tasks(
move |sleeping| {
let inner1 = inner1.clone();
async move {
let lock = inner1.lock().await;
load_save(sleeping, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
},
move |_shutting_down| {
let inner3 = inner3.clone();
async move {
let lock = inner3.lock().await;
load_save(false, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
},
move |_lid_closed| {
// on lid change
async move {}
},
move |_power_plugged| {
// power change
async move {}
},
)
.await;
let ctrl2 = self.0.clone();
let ctrl = self.0.lock().await;
if ctrl.led_node.has_brightness_control() {
let watch = ctrl.led_node.monitor_brightness()?;
tokio::spawn(async move {
let mut buffer = [0; 32];
watch
.into_event_stream(&mut buffer)
.unwrap()
.for_each(|_| async {
if let Some(lock) = ctrl2.try_lock() {
load_save(true, lock).unwrap(); // unwrap as we want to
// bomb out of the task
}
})
.await;
});
}
Ok(())
}
}
impl crate::Reloadable for CtrlAuraZbus {
async fn reload(&mut self) -> Result<(), RogError> {
let mut ctrl = self.0.lock().await;
debug!("reloading keyboard mode");
ctrl.write_current_config_mode()?;
debug!("reloading power states");
ctrl.set_power_states().map_err(|err| warn!("{err}")).ok();
Ok(())
}
}

286
asusd/src/ctrl_fancurves.rs Normal file
View File

@@ -0,0 +1,286 @@
use std::path::PathBuf;
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_profiles::error::ProfileError;
use rog_profiles::fan_curve_set::CurveData;
use rog_profiles::{find_fan_curve_node, FanCurvePU, FanCurveProfiles};
use serde_derive::{Deserialize, Serialize};
use tokio::sync::Mutex;
use zbus::{interface, Connection, SignalContext};
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";
#[derive(Deserialize, Serialize, Debug, Default)]
pub struct FanCurveConfig {
pub profiles: FanCurveProfiles,
#[serde(skip)]
pub current: u8,
}
impl StdConfig for FanCurveConfig {
/// Create a new config. The defaults are zeroed so the device must be read
/// to get the actual device defaults.
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
"fan_curves.ron".to_owned()
}
fn config_dir() -> std::path::PathBuf {
PathBuf::from(CONFIG_PATH_BASE)
}
}
impl StdConfigLoad for FanCurveConfig {}
#[derive(Debug, Clone)]
pub struct CtrlFanCurveZbus {
config: Arc<Mutex<FanCurveConfig>>,
platform: RogPlatform,
}
// Non-zbus-derive impl
impl CtrlFanCurveZbus {
pub fn new() -> Result<Self, RogError> {
let platform = RogPlatform::new()?;
if platform.has_throttle_thermal_policy() {
info!("Device has profile control available");
find_fan_curve_node()?;
info!("Device has fan curves available");
let mut config = FanCurveConfig::new().load();
let mut fan_curves = FanCurveProfiles::default();
// Only do defaults if the config doesn't already exist\
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,
] {
// 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())?;
let mut dev = find_fan_curve_node()?;
fan_curves.set_active_curve_to_defaults(this, &mut dev)?;
info!("{this:?}:");
for curve in fan_curves.get_fan_curves_for(this) {
info!("{}", String::from(curve));
}
}
platform.set_throttle_thermal_policy(current)?;
config.profiles = fan_curves;
config.write();
} else {
info!("Fan curves previously stored, loading...");
config = config.load();
}
return Ok(Self {
config: Arc::new(Mutex::new(config)),
platform,
});
}
Err(ProfileError::NotSupported.into())
}
}
#[interface(name = "org.asuslinux.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,
enabled: bool,
) -> zbus::fdo::Result<()> {
self.config
.lock()
.await
.profiles
.set_profile_curves_enabled(profile, enabled);
self.config
.lock()
.await
.profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
self.config.lock().await.write();
Ok(())
}
/// Set a single fan curve for a profile to enabled status. Will also
/// activate a fan curve if in the same profile mode
async fn set_profile_fan_curve_enabled(
&mut self,
profile: ThrottlePolicy,
fan: FanCurvePU,
enabled: bool,
) -> zbus::fdo::Result<()> {
self.config
.lock()
.await
.profiles
.set_profile_fan_curve_enabled(profile, fan, enabled);
self.config
.lock()
.await
.profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
self.config.lock().await.write();
Ok(())
}
/// Get the fan-curve data for the currently active ThrottlePolicy
async fn fan_curve_data(
&mut self,
profile: ThrottlePolicy,
) -> zbus::fdo::Result<Vec<CurveData>> {
let curve = self
.config
.lock()
.await
.profiles
.get_fan_curves_for(profile)
.to_vec();
Ok(curve)
}
/// Set the fan curve for the specified profile.
/// Will also activate the fan curve if the user is in the same mode.
async fn set_fan_curve(
&mut self,
profile: ThrottlePolicy,
curve: CurveData,
) -> zbus::fdo::Result<()> {
self.config
.lock()
.await
.profiles
.save_fan_curve(curve, profile)?;
let active: ThrottlePolicy = self.platform.get_throttle_thermal_policy()?.into();
if active == profile {
self.config
.lock()
.await
.profiles
.write_profile_curve_to_platform(profile, &mut find_fan_curve_node()?)?;
}
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curves to the defaults of the
/// platform.
///
/// 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())?;
self.config
.lock()
.await
.profiles
.set_active_curve_to_defaults(profile, &mut find_fan_curve_node()?)?;
self.platform.set_throttle_thermal_policy(active)?;
self.config.lock().await.write();
Ok(())
}
/// Reset the stored (self) and device curve to the defaults of the
/// platform.
///
/// Each platform_profile has a different default and the defualt can be
/// read only for the currently active profile.
async fn reset_profile_curves(&self, profile: ThrottlePolicy) -> zbus::fdo::Result<()> {
let active = self.platform.get_throttle_thermal_policy()?;
self.platform.set_throttle_thermal_policy(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)?;
self.config.lock().await.write();
Ok(())
}
}
impl crate::ZbusRun for CtrlFanCurveZbus {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, FAN_CURVE_ZBUS_PATH, server).await;
}
}
impl CtrlTask for CtrlFanCurveZbus {
fn zbus_path() -> &'static str {
FAN_CURVE_ZBUS_PATH
}
async fn create_tasks(&self, _signal_ctxt: SignalContext<'static>) -> Result<(), RogError> {
let watch_throttle_thermal_policy = self.platform.monitor_throttle_thermal_policy()?;
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) {
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}");
}) {
if profile != config.lock().await.current {
fan_curves
.lock()
.await
.profiles
.write_profile_curve_to_platform(
profile.into(),
&mut find_fan_curve_node().unwrap(),
)
.map_err(|e| warn!("write_profile_curve_to_platform, {}", e))
.ok();
config.lock().await.current = profile;
}
}
}
}
});
Ok(())
}
}
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 mut config = self.config.lock().await;
if let Ok(mut device) = find_fan_curve_node() {
config
.profiles
.write_profile_curve_to_platform(active, &mut device)?;
}
Ok(())
}
}

1025
asusd/src/ctrl_platform.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
use config_traits::{StdConfig, StdConfigLoad};
use rog_slash::{DeviceState, SlashMode};
use serde_derive::{Deserialize, Serialize};
const CONFIG_FILE: &str = "slash.ron";
/// Config for base system actions for the anime display
#[derive(Deserialize, Serialize, Debug)]
pub struct SlashConfig {
pub slash_enabled: bool,
pub slash_brightness: u8,
pub slash_interval: u8,
pub slash_mode: SlashMode,
}
impl Default for SlashConfig {
fn default() -> Self {
SlashConfig {
slash_enabled: true,
slash_brightness: 255,
slash_interval: 0,
slash_mode: SlashMode::Bounce,
}
}
}
impl StdConfig for SlashConfig {
fn new() -> Self {
Self::default()
}
fn file_name(&self) -> String {
CONFIG_FILE.to_owned()
}
fn config_dir() -> std::path::PathBuf {
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
}
}
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,
}
}
}

View File

@@ -0,0 +1,98 @@
pub mod config;
pub mod trait_impls;
use config_traits::{StdConfig, StdConfigLoad};
use rog_platform::hid_raw::HidRaw;
use rog_platform::usb_raw::USBRaw;
use rog_slash::error::SlashError;
use rog_slash::usb::{get_slash_type, pkt_set_mode, pkt_set_options, pkts_for_init};
use rog_slash::{SlashMode, SlashType};
use crate::ctrl_slash::config::SlashConfig;
use crate::error::RogError;
enum Node {
Usb(USBRaw),
Hid(HidRaw),
}
impl Node {
pub fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
// TODO: map and pass on errors
match self {
Node::Usb(u) => {
u.write_bytes(message).ok();
}
Node::Hid(h) => {
h.write_bytes(message).ok();
}
}
Ok(())
}
}
pub struct CtrlSlash {
node: Node,
config: SlashConfig,
}
impl CtrlSlash {
#[inline]
pub fn new() -> Result<CtrlSlash, RogError> {
let slash_type = get_slash_type()?;
if matches!(slash_type, SlashType::Unknown | SlashType::Unsupported) {
return Err(RogError::Slash(SlashError::NoDevice));
}
let usb = USBRaw::new(rog_slash::usb::PROD_ID).ok();
let hid = HidRaw::new(rog_slash::usb::PROD_ID_STR).ok();
let node = if usb.is_some() {
unsafe { Node::Usb(usb.unwrap_unchecked()) }
} else if hid.is_some() {
unsafe { Node::Hid(hid.unwrap_unchecked()) }
} else {
return Err(RogError::NotSupported);
};
let ctrl = CtrlSlash {
node,
config: SlashConfig::new().load(),
};
ctrl.do_initialization()?;
Ok(ctrl)
}
fn do_initialization(&self) -> Result<(), RogError> {
let init_packets = pkts_for_init();
self.node.write_bytes(&init_packets[0])?;
self.node.write_bytes(&init_packets[1])?;
// Apply config upon initialization
let option_packets = pkt_set_options(
self.config.slash_enabled,
self.config.slash_brightness,
self.config.slash_interval,
);
self.node.write_bytes(&option_packets)?;
let mode_packets = pkt_set_mode(self.config.slash_mode);
self.node.write_bytes(&mode_packets[0])?;
self.node.write_bytes(&mode_packets[1])?;
Ok(())
}
pub fn set_options(&self, enabled: bool, brightness: u8, interval: u8) -> Result<(), RogError> {
let command_packets = pkt_set_options(enabled, brightness, interval);
self.node.write_bytes(&command_packets)?;
Ok(())
}
pub fn set_slash_mode(&self, slash_mode: SlashMode) -> Result<(), RogError> {
let command_packets = pkt_set_mode(slash_mode);
self.node.write_bytes(&command_packets[0])?;
self.node.write_bytes(&command_packets[1])?;
Ok(())
}
}

View File

@@ -0,0 +1,165 @@
use std::sync::Arc;
use config_traits::StdConfig;
use log::warn;
use rog_slash::usb::{pkt_set_mode, pkt_set_options};
use rog_slash::{DeviceState, SlashMode};
use zbus::export::futures_util::lock::Mutex;
use zbus::{interface, Connection, SignalContext};
use crate::ctrl_slash::CtrlSlash;
use crate::error::RogError;
pub const SLASH_ZBUS_NAME: &str = "Slash";
pub const SLASH_ZBUS_PATH: &str = "/org/asuslinux";
#[derive(Clone)]
pub struct CtrlSlashZbus(pub Arc<Mutex<CtrlSlash>>);
/// The struct with the main dbus methods requires this trait
impl crate::ZbusRun for CtrlSlashZbus {
async fn add_to_server(self, server: &mut Connection) {
Self::add_to_server_helper(self, SLASH_ZBUS_PATH, server).await;
}
}
#[interface(name = "org.asuslinux.Slash")]
impl CtrlSlashZbus {
/// Get enabled or not
#[zbus(property)]
async fn enabled(&self) -> bool {
let lock = self.0.lock().await;
lock.config.slash_enabled
}
/// Set enabled true or false
#[zbus(property)]
async fn set_enabled(&self, enabled: bool) {
let mut lock = self.0.lock().await;
let brightness = if enabled && lock.config.slash_brightness == 0 {
0x88
} else {
lock.config.slash_brightness
};
lock.node
.write_bytes(&pkt_set_options(
enabled,
brightness,
lock.config.slash_interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_enabled = enabled;
lock.config.slash_brightness = brightness;
lock.config.write();
}
/// Get brightness level
#[zbus(property)]
async fn brightness(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_brightness
}
/// Set brightness level
#[zbus(property)]
async fn set_brightness(&self, brightness: u8) {
let mut lock = self.0.lock().await;
let enabled = brightness > 0;
lock.node
.write_bytes(&pkt_set_options(
enabled,
brightness,
lock.config.slash_interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_enabled = enabled;
lock.config.slash_brightness = brightness;
lock.config.write();
}
#[zbus(property)]
async fn interval(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_interval
}
/// Set interval between slash animations (0-255)
#[zbus(property)]
async fn set_interval(&self, interval: u8) {
let mut lock = self.0.lock().await;
lock.node
.write_bytes(&pkt_set_options(
lock.config.slash_enabled,
lock.config.slash_brightness,
interval,
))
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_interval = interval;
lock.config.write();
}
#[zbus(property)]
async fn slash_mode(&self) -> u8 {
let lock = self.0.lock().await;
lock.config.slash_interval
}
/// Set interval between slash animations (0-255)
#[zbus(property)]
async fn set_slash_mode(&self, slash_mode: SlashMode) {
let mut lock = self.0.lock().await;
let command_packets = pkt_set_mode(slash_mode);
lock.node
.write_bytes(&command_packets[0])
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.node
.write_bytes(&command_packets[1])
.map_err(|err| {
warn!("ctrl_slash::set_options {}", err);
})
.ok();
lock.config.slash_mode = slash_mode;
lock.config.write();
}
/// Get the device state as stored by asusd
// #[zbus(property)]
async fn device_state(&self) -> DeviceState {
let lock = self.0.lock().await;
DeviceState::from(&lock.config)
}
}
impl crate::CtrlTask for CtrlSlashZbus {
fn zbus_path() -> &'static str {
SLASH_ZBUS_PATH
}
async fn create_tasks(&self, _: SignalContext<'static>) -> Result<(), RogError> {
Ok(())
}
}
impl crate::Reloadable for CtrlSlashZbus {
async fn reload(&mut self) -> Result<(), RogError> {
Ok(())
}
}

134
asusd/src/daemon.rs Normal file
View File

@@ -0,0 +1,134 @@
use std::env;
use std::error::Error;
use std::sync::Arc;
use ::zbus::export::futures_util::lock::Mutex;
use ::zbus::Connection;
use asusd::config::Config;
use asusd::ctrl_anime::trait_impls::CtrlAnimeZbus;
use asusd::ctrl_anime::CtrlAnime;
use asusd::ctrl_aura::manager::AuraManager;
use asusd::ctrl_fancurves::CtrlFanCurveZbus;
use asusd::ctrl_platform::CtrlPlatform;
use asusd::ctrl_slash::trait_impls::CtrlSlashZbus;
use asusd::ctrl_slash::CtrlSlash;
use asusd::{print_board_info, start_tasks, CtrlTask, DBUS_NAME};
use config_traits::{StdConfig, StdConfigLoad1};
use log::{error, info};
use zbus::fdo::ObjectManager;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// console_subscriber::init();
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()
.target(env_logger::Target::Stdout)
.format_timestamp(None)
.init();
let is_service = match env::var_os("IS_SERVICE") {
Some(val) => val == "1",
None => false,
};
if !is_service {
println!("asusd schould be only run from the right systemd service");
println!(
"do not run in your terminal, if you need an logs please use journalctl -b -u asusd"
);
println!("asusd will now exit");
return Ok(());
}
info!(" daemon v{}", asusd::VERSION);
info!(" rog-anime v{}", rog_anime::VERSION);
info!(" rog-slash v{}", rog_slash::VERSION);
info!(" rog-aura v{}", rog_aura::VERSION);
info!(" rog-profiles v{}", rog_profiles::VERSION);
info!("rog-platform v{}", rog_platform::VERSION);
start_daemon().await?;
Ok(())
}
/// The actual main loop for the daemon
async fn start_daemon() -> Result<(), Box<dyn Error>> {
// let supported = SupportedFunctions::get_supported();
print_board_info();
// println!("{:?}", supported.supported_functions());
// Start zbus server
let mut connection = Connection::system().await?;
connection
.object_server()
.at("/org/asuslinux", ObjectManager)
.await
.unwrap();
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;
match CtrlFanCurveZbus::new() {
Ok(ctrl) => {
let sig_ctx = CtrlFanCurveZbus::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("FanCurves: {}", err);
}
}
match CtrlPlatform::new(
config.clone(),
&cfg_path,
CtrlPlatform::signal_context(&connection)?,
) {
Ok(ctrl) => {
let sig_ctx = CtrlPlatform::signal_context(&connection)?;
start_tasks(ctrl, &mut connection, sig_ctx).await?;
}
Err(err) => {
error!("CtrlPlatform: {}", err);
}
}
match CtrlAnime::new() {
Ok(ctrl) => {
let zbus = CtrlAnimeZbus(Arc::new(Mutex::new(ctrl)));
let sig_ctx = CtrlAnimeZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?;
}
Err(err) => {
info!("AniMe control: {}", err);
}
}
match CtrlSlash::new() {
Ok(ctrl) => {
let zbus = CtrlSlashZbus(Arc::new(Mutex::new(ctrl)));
// Currently, the Slash has no need for a loop watching power events, however,
// it could be cool to have the slash do some power-on/off animation
// (It has a built-in power on animation which plays when u plug in the power
// supply)
let sig_ctx = CtrlSlashZbus::signal_context(&connection)?;
start_tasks(zbus, &mut connection, sig_ctx).await?;
}
Err(err) => {
info!("AniMe control: {}", err);
}
}
let _ = AuraManager::new(connection.clone()).await?;
// Request dbus name after finishing initalizing all functions
connection.request_name(DBUS_NAME).await?;
loop {
// This is just a blocker to idle and ensure the reator reacts
connection.executor().tick().await;
}
}

144
asusd/src/error.rs Normal file
View File

@@ -0,0 +1,144 @@
use std::convert::From;
use std::fmt;
use config_traits::ron;
use rog_anime::error::AnimeError;
use rog_platform::error::PlatformError;
use rog_profiles::error::ProfileError;
use rog_slash::error::SlashError;
#[derive(Debug)]
pub enum RogError {
ParseVendor,
ParseLed,
MissingProfile(String),
Udev(String, std::io::Error),
Path(String, std::io::Error),
Read(String, std::io::Error),
Write(String, std::io::Error),
NotSupported,
NotFound(String),
DoTask(String),
MissingFunction(String),
MissingLedBrightNode(String, std::io::Error),
ReloadFail(String),
Profiles(ProfileError),
Initramfs(String),
Modprobe(String),
Io(std::io::Error),
Zbus(zbus::Error),
ChargeLimit(u8),
AuraEffectNotSupported,
NoAuraKeyboard,
NoAuraNode,
Anime(AnimeError),
Slash(SlashError),
Platform(PlatformError),
SystemdUnitAction(String),
SystemdUnitWaitTimeout(String),
Command(String, std::io::Error),
ParseRon(ron::Error),
}
impl fmt::Display for RogError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
RogError::ParseLed => write!(f, "Parse LED error"),
RogError::MissingProfile(profile) => write!(f, "Profile does not exist {}", profile),
RogError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
RogError::Path(path, error) => write!(f, "Path {}: {}", path, error),
RogError::Read(path, error) => write!(f, "Read {}: {}", path, error),
RogError::Write(path, error) => write!(f, "Write {}: {}", path, error),
RogError::NotSupported => write!(f, "Not supported"),
RogError::NotFound(deets) => write!(f, "Not found: {}", deets),
RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(
f,
"Led node at {} is missing, please check you have the required patch or dkms \
module installed: {}",
path, error
),
RogError::ReloadFail(deets) => write!(f, "Reload error: {}", deets),
RogError::Profiles(deets) => write!(f, "Profile error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
RogError::ChargeLimit(value) => {
write!(f, "Invalid charging limit, not in range 20-100%: {}", value)
}
RogError::AuraEffectNotSupported => write!(f, "Aura effect not supported"),
RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"),
RogError::NoAuraNode => write!(f, "No Aura keyboard node found"),
RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets),
RogError::Slash(deets) => write!(f, "Slash error: {}", deets),
RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets),
RogError::SystemdUnitAction(action) => {
write!(f, "systemd unit action {} failed", action)
}
RogError::SystemdUnitWaitTimeout(state) => {
write!(
f,
"Timed out waiting for systemd unit change {} state",
state
)
}
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
RogError::ParseRon(error) => write!(f, "Parse config error: {}", error),
}
}
}
impl std::error::Error for RogError {}
impl From<ProfileError> for RogError {
fn from(err: ProfileError) -> Self {
RogError::Profiles(err)
}
}
impl From<AnimeError> for RogError {
fn from(err: AnimeError) -> Self {
RogError::Anime(err)
}
}
impl From<SlashError> for RogError {
fn from(err: SlashError) -> Self {
RogError::Slash(err)
}
}
impl From<PlatformError> for RogError {
fn from(err: PlatformError) -> Self {
RogError::Platform(err)
}
}
impl From<zbus::Error> for RogError {
fn from(err: zbus::Error) -> Self {
RogError::Zbus(err)
}
}
impl From<std::io::Error> for RogError {
fn from(err: std::io::Error) -> Self {
RogError::Io(err)
}
}
impl From<ron::Error> for RogError {
fn from(err: ron::Error) -> Self {
RogError::ParseRon(err)
}
}
impl From<RogError> for zbus::fdo::Error {
#[inline]
fn from(err: RogError) -> Self {
zbus::fdo::Error::Failed(format!("{}", err))
}
}

314
asusd/src/lib.rs Normal file
View File

@@ -0,0 +1,314 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
/// Control of anime matrix display
pub mod ctrl_anime;
/// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_aura;
/// 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;
/// Control of Slash led bar
pub mod ctrl_slash;
pub mod error;
use std::future::Future;
use std::time::Duration;
use dmi_id::DMIID;
use futures_lite::stream::StreamExt;
use log::{debug, info, warn};
use logind_zbus::manager::ManagerProxy;
use tokio::time::sleep;
use zbus::zvariant::ObjectPath;
use zbus::{CacheProperties, Connection, SignalContext};
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";
/// This macro adds a function which spawns an `inotify` task on the passed in
/// `Executor`.
///
/// The generated function is `watch_<name>()`. Self requires the following
/// methods to be available:
/// - `<name>() -> SomeValue`, functionally is a getter, but is allowed to have
/// side effects.
/// - `notify_<name>(SignalContext, SomeValue)`
///
/// In most cases if `SomeValue` is stored in a config then `<name>()` getter is
/// expected to update it. The getter should *never* write back to the path or
/// attribute that is being watched or an infinite loop will occur.
///
/// # Example
///
/// ```ignore
/// impl RogPlatform {
/// task_watch_item!(panel_od platform);
/// task_watch_item!(gpu_mux_mode platform);
/// }
/// ```\
/// // TODO: this is kind of useless if it can't trigger some action
#[macro_export]
macro_rules! task_watch_item {
($name:ident $name_str:literal $self_inner:ident) => {
concat_idents::concat_idents!(fn_name = watch_, $name {
async fn fn_name(
&self,
signal_ctxt: SignalContext<'static>,
) -> Result<(), RogError> {
use zbus::export::futures_util::StreamExt;
let ctrl = self.clone();
concat_idents::concat_idents!(watch_fn = monitor_, $name {
match self.$self_inner.watch_fn() {
Ok(watch) => {
tokio::spawn(async move {
let mut buffer = [0; 32];
watch.into_event_stream(&mut buffer).unwrap().for_each(|_| async {
if let Ok(value) = ctrl.$name() { // get new value from zbus method
if ctrl.config.lock().await.$name != value {
log::debug!("{} was changed to {} externally", $name_str, value);
concat_idents::concat_idents!(notif_fn = $name, _changed {
ctrl.notif_fn(&signal_ctxt).await.ok();
});
let mut lock = ctrl.config.lock().await;
lock.$name = value;
lock.write();
}
}
}).await;
});
}
Err(e) => info!("inotify watch failed: {}. You can ignore this if your device does not support the feature", e),
}
});
Ok(())
}
});
};
}
#[macro_export]
macro_rules! task_watch_item_notify {
($name:ident $self_inner:ident) => {
concat_idents::concat_idents!(fn_name = watch_, $name {
async fn fn_name(
&self,
signal_ctxt: SignalContext<'static>,
) -> Result<(), RogError> {
use zbus::export::futures_util::StreamExt;
let ctrl = self.clone();
concat_idents::concat_idents!(watch_fn = monitor_, $name {
match self.$self_inner.watch_fn() {
Ok(watch) => {
tokio::spawn(async move {
let mut buffer = [0; 32];
watch.into_event_stream(&mut buffer).unwrap().for_each(|_| async {
concat_idents::concat_idents!(notif_fn = $name, _changed {
ctrl.notif_fn(&signal_ctxt).await.ok();
});
}).await;
});
}
Err(e) => info!("inotify watch failed: {}. You can ignore this if your device does not support the feature", e),
}
});
Ok(())
}
});
};
}
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
pub fn print_board_info() {
let dmi = DMIID::new().unwrap_or_default();
info!("Product family: {}", dmi.product_family);
info!("Board name: {}", dmi.board_name);
}
pub trait Reloadable {
fn reload(&mut self) -> impl Future<Output = Result<(), RogError>> + Send;
}
pub trait ReloadAndNotify {
type Data: Send;
fn reload_and_notify(
&mut self,
signal_context: &SignalContext<'static>,
data: Self::Data,
) -> impl Future<Output = Result<(), RogError>> + Send;
}
pub trait ZbusRun {
fn add_to_server(self, server: &mut Connection) -> impl Future<Output = ()> + Send;
fn add_to_server_helper(
iface: impl zbus::Interface,
path: &str,
server: &mut Connection,
) -> impl Future<Output = ()> + Send {
async move {
server
.object_server()
.at(&ObjectPath::from_str_unchecked(path), iface)
.await
.map_err(|err| {
warn!("{}: add_to_server {}", path, err);
err
})
.ok();
}
}
}
/// Set up a task to run on the async executor
pub trait CtrlTask {
fn zbus_path() -> &'static str;
fn signal_context(connection: &Connection) -> Result<SignalContext<'static>, zbus::Error> {
SignalContext::new(connection, Self::zbus_path())
}
/// Implement to set up various tasks that may be required, using the
/// `Executor`. No blocking loops are allowed, or they must be run on a
/// separate thread.
fn create_tasks(
&self,
signal: SignalContext<'static>,
) -> impl Future<Output = Result<(), RogError>> + Send;
// /// Create a timed repeating task
// async fn repeating_task(&self, millis: u64, mut task: impl FnMut() + Send +
// 'static) { use std::time::Duration;
// use tokio::time;
// let mut timer = time::interval(Duration::from_millis(millis));
// tokio::spawn(async move {
// timer.tick().await;
// task();
// });
// }
/// Free helper method to create tasks to run on: sleep, wake, shutdown,
/// boot
///
/// The closures can potentially block, so execution time should be the
/// minimal possible such as save a variable.
fn create_sys_event_tasks<Fut1, Fut2, Fut3, Fut4, F1, F2, F3, F4>(
&self,
mut on_prepare_for_sleep: F1,
mut on_prepare_for_shutdown: F2,
mut on_lid_change: F3,
mut on_external_power_change: F4,
) -> impl Future<Output = ()> + Send
where
F1: FnMut(bool) -> Fut1 + Send + 'static,
F2: FnMut(bool) -> Fut2 + Send + 'static,
F3: FnMut(bool) -> Fut3 + Send + 'static,
F4: FnMut(bool) -> Fut4 + Send + 'static,
Fut1: Future<Output = ()> + Send,
Fut2: Future<Output = ()> + Send,
Fut3: Future<Output = ()> + Send,
Fut4: Future<Output = ()> + Send,
{
async {
let connection = Connection::system()
.await
.expect("Controller could not create dbus connection");
let manager = ManagerProxy::builder(&connection)
.cache_properties(CacheProperties::No)
.build()
.await
.expect("Controller could not create ManagerProxy");
let manager1 = manager.clone();
tokio::spawn(async move {
if let Ok(mut notif) = manager1.receive_prepare_for_shutdown().await {
while let Some(event) = notif.next().await {
// blocks thread :|
if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_shutdown({})", args.start);
on_prepare_for_shutdown(args.start).await;
}
}
}
});
let manager2 = manager.clone();
tokio::spawn(async move {
if let Ok(mut notif) = manager2.receive_prepare_for_sleep().await {
while let Some(event) = notif.next().await {
// blocks thread :|
if let Ok(args) = event.args() {
debug!("Doing on_prepare_for_sleep({})", args.start);
on_prepare_for_sleep(args.start).await;
}
}
}
});
let manager3 = manager.clone();
tokio::spawn(async move {
let mut last_power = manager3.on_external_power().await.unwrap_or_default();
loop {
if let Ok(next) = manager3.on_external_power().await {
if next != last_power {
last_power = next;
on_external_power_change(next).await;
}
}
sleep(Duration::from_secs(2)).await;
}
});
tokio::spawn(async move {
let mut last_lid = manager.lid_closed().await.unwrap_or_default();
// need to loop on these as they don't emit signals
loop {
if let Ok(next) = manager.lid_closed().await {
if next != last_lid {
last_lid = next;
on_lid_change(next).await;
}
}
sleep(Duration::from_secs(2)).await;
}
});
}
}
}
pub trait GetSupported {
type A;
fn get_supported() -> Self::A;
}
pub async fn start_tasks<T>(
mut zbus: T,
connection: &mut Connection,
signal_ctx: SignalContext<'static>,
) -> Result<(), RogError>
where
T: ZbusRun + Reloadable + CtrlTask + Clone,
{
let zbus_clone = zbus.clone();
zbus.reload()
.await
.unwrap_or_else(|err| warn!("Controller error: {}", err));
zbus.add_to_server(connection).await;
zbus_clone.create_tasks(signal_ctx).await.ok();
Ok(())
}

18
config-traits/Cargo.toml Normal file
View File

@@ -0,0 +1,18 @@
[package]
name = "config-traits"
license.workspace = true
version.workspace = true
readme.workspace = true
authors.workspace = true
repository.workspace = true
homepage.workspace = true
edition.workspace = true
[dependencies]
serde.workspace = true
ron.workspace = true
log.workspace = true
[dev-dependencies]
cargo-husky.workspace = true

10
config-traits/README.md Normal file
View File

@@ -0,0 +1,10 @@
# config-traits
`config_traits` is a crate that broke out from the requirement to manage various
different config files, including parsing from different formats and updating
them from previous versions where fields or names are changed in some way.
The end canonical file format is `.ron` as this supports rust types well, and includes
the ability to add commenting, and is less verbose than `json`. Currently the crate will
also try to parse from `json` and `toml` if the `ron` parsing fails, then update to `ron`
format.

328
config-traits/src/lib.rs Normal file
View File

@@ -0,0 +1,328 @@
//! `config_traits` is a crate that broke out from the requirement to manage
//! various different config files, including parsing from different formats and
//! updating them from previous versions where fields or names are changed in
//! some way.
//!
//! The end canonical file format is `.ron` as this supports rust types well
use std::fs::{self, create_dir, File, OpenOptions};
use std::io::{Read, Write};
use std::path::PathBuf;
use log::{error, warn};
pub use ron;
use ron::ser::PrettyConfig;
use serde::de::DeserializeOwned;
use serde::Serialize;
/// Config file helper traits. Only `new()` and `file_name()` are required to be
/// implemented, the rest are intended to be free methods.
pub trait StdConfig
where
Self: Serialize + DeserializeOwned,
{
/// Taking over the standard `new()` to ensure things can be generic
fn new() -> Self;
/// Return the config files names, such as `wibble.cfg`
fn file_name(&self) -> String;
/// Return the full path to the directory the config file resides in
fn config_dir() -> PathBuf;
/// Return the full path to the config file
fn file_path(&self) -> PathBuf {
let mut config = Self::config_dir();
if !config.exists() {
create_dir(config.as_path())
.unwrap_or_else(|e| panic!("Could not create {:?} {e}", Self::config_dir()));
}
config.push(self.file_name());
let mut do_rename = !config.exists();
let mut cfg_old = config.clone();
// Migrating all configs to .ron format, so we do need to check for older ones
if do_rename {
warn!("Config {cfg_old:?} does not exist, looking for .cfg next");
cfg_old.pop();
let tmp = self.file_name();
let parts: Vec<_> = tmp.split('.').collect();
cfg_old.push(format!("{}.cfg", parts[0]));
}
if do_rename && cfg_old.exists() {
// Now we gotta rename it
warn!("Renaming {cfg_old:?} to {config:?}");
std::fs::rename(&cfg_old, &config).unwrap_or_else(|err| {
error!(
"Could not rename. Please remove {} then restart service: Error {}",
self.file_name(),
err
);
});
do_rename = false;
}
if do_rename && !cfg_old.exists() {
warn!("Config {cfg_old:?} does not exist, looking for .conf next");
cfg_old.pop();
let tmp = self.file_name();
let parts: Vec<_> = tmp.split('.').collect();
cfg_old.push(format!("{}.conf", parts[0]));
}
if do_rename && cfg_old.exists() {
// Now we gotta rename it
warn!("Renaming {cfg_old:?} to {config:?}");
std::fs::rename(&cfg_old, &config).unwrap_or_else(|err| {
error!(
"Could not rename. Please remove {} then restart service: Error {}",
self.file_name(),
err
);
});
}
config
}
/// Directly open the config file for read and write. If the config file
/// does not exist it is created, including the directories the file
/// resides in.
fn file_open(&self) -> File {
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(self.file_path())
.unwrap_or_else(|e| panic!("Could not open {:?} {e}", self.file_path()))
}
/// Open and parse the config file to self from ron format
fn read(&mut self) {
if let Ok(data) = fs::read_to_string(self.file_path()) {
if data.is_empty() {
warn!("File is empty {:?}", self.file_path());
} else if let Ok(data) = ron::from_str(&data) {
*self = data;
} else {
warn!("Could not deserialise {:?}", self.file_path());
}
}
}
/// Open and parse the config file to self from ron format
fn read_new(&self) -> Option<Self> {
if let Ok(data) = fs::read_to_string(self.file_path()) {
if data.is_empty() {
warn!("File is empty {:?}", self.file_path());
} else if let Ok(data) = ron::from_str(&data) {
return Some(data);
} else {
warn!("Could not deserialise {:?}", self.file_path());
}
}
None
}
/// Write the config file data to pretty ron format
fn write(&self) {
let mut file = match File::create(self.file_path()) {
Ok(data) => data,
Err(e) => {
error!(
"Couldn't overwrite config {:?}, error: {e}",
self.file_path()
);
return;
}
};
let ron = match ron::ser::to_string_pretty(&self, PrettyConfig::new().depth_limit(4)) {
Ok(data) => data,
Err(e) => {
error!("Parse {:?} to RON failed, error: {e}", self.file_path());
return;
}
};
file.write_all(ron.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
/// Renames the existing file to `<file>-old`
fn rename_file_old(&self) {
warn!(
"Renaming {} to {}-old and recreating config",
self.file_name(),
self.file_name()
);
let mut cfg_old = self.file_path().to_string_lossy().to_string();
cfg_old.push_str("-old");
std::fs::rename(self.file_path(), cfg_old).unwrap_or_else(|err| {
error!(
"Could not rename. Please remove {} then restart service: Error {}",
self.file_name(),
err
);
});
}
}
#[macro_export]
macro_rules! std_config_load {
($trait_name:ident: $($generic:ident),*) => {
/// Base trait for loading/parsing. This is intended to be used to help update
/// configs to new versions
///
/// # Example
/// ```rust
/// use std::path::PathBuf;
/// use serde::{Deserialize, Serialize};
/// use config_traits::{StdConfig, StdConfigLoad2};
///
/// #[derive(Deserialize, Serialize, Debug)]
/// struct FanCurveConfigOld {}
///
/// #[derive(Deserialize, Serialize, Debug)]
/// struct FanCurveConfigOlder {}
///
/// #[derive(Deserialize, Serialize, Debug)]
/// struct FanCurveConfig {}
///
/// impl From<FanCurveConfigOld> for FanCurveConfig {
/// fn from(_: FanCurveConfigOld) -> Self { Self {} }
/// }
///
/// impl From<FanCurveConfigOlder> for FanCurveConfig {
/// fn from(_: FanCurveConfigOlder) -> Self { Self {} }
/// }
///
/// impl StdConfig for FanCurveConfig {
/// fn new() -> Self { Self {} }
///
/// fn file_name(&self) -> std::string::String { "test_name.conf".to_owned() }
///
/// fn config_dir() -> PathBuf { PathBuf::from("/tmp") }
/// }
///
/// impl StdConfigLoad2<FanCurveConfigOld, FanCurveConfigOlder> for FanCurveConfig {}
/// ```
///
/// If all of the generics fails to parse, then the old config is renamed and a
/// new one created
pub trait $trait_name<$($generic),*>
where
Self: $crate::StdConfig +std::fmt::Debug + DeserializeOwned + Serialize,
$($generic: DeserializeOwned + Into<Self>),*
{
fn load(mut self) -> Self {
let mut file = self.file_open();
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len != 0 {
if let Ok(data) = ron::from_str(&buf) {
self = data;
log::info!("Parsed RON for {:?}", std::any::type_name::<Self>());
} $(else if let Ok(data) = ron::from_str::<$generic>(&buf) {
self = data.into();
log::info!("New version failed, trying previous: Parsed RON for {:?}", std::any::type_name::<$generic>());
})* else {
self.rename_file_old();
self = Self::new();
}
} else {
error!("Config file {} zero read length", self.file_name());
}
}
self.write();
self
}
}
};
}
std_config_load!(StdConfigLoad:);
std_config_load!(StdConfigLoad1: T1);
std_config_load!(StdConfigLoad2: T1, T2);
std_config_load!(StdConfigLoad3: T1, T2, T3);
std_config_load!(StdConfigLoad4: T1, T2, T3, T4);
#[cfg(test)]
mod tests {
use std::path::PathBuf;
#[test]
fn check_macro_from_1() {
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Test {}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Old1 {}
impl crate::StdConfig for Test {
fn new() -> Self {
Self {}
}
fn file_name(&self) -> String {
String::new()
}
fn config_dir() -> PathBuf {
PathBuf::new()
}
}
impl From<Old1> for Test {
fn from(_: Old1) -> Self {
Self {}
}
}
impl crate::StdConfigLoad1<Old1> for Test {}
}
#[test]
fn check_macro_from_3() {
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Test {}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Old1 {}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Old2 {}
#[derive(serde::Deserialize, serde::Serialize, Debug)]
struct Old3 {}
impl crate::StdConfig for Test {
fn new() -> Self {
Self {}
}
fn file_name(&self) -> String {
String::new()
}
fn config_dir() -> PathBuf {
PathBuf::new()
}
}
impl From<Old1> for Test {
fn from(_: Old1) -> Self {
Self {}
}
}
impl From<Old2> for Test {
fn from(_: Old2) -> Self {
Self {}
}
}
impl From<Old3> for Test {
fn from(_: Old3) -> Self {
Self {}
}
}
impl crate::StdConfigLoad3<Old1, Old2, Old3> for Test {}
}
}

11
cpuctl/Cargo.toml Normal file
View File

@@ -0,0 +1,11 @@
[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]

14
cpuctl/src/lib.rs Normal file
View File

@@ -0,0 +1,14 @@
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

@@ -1,44 +0,0 @@
[package]
name = "daemon"
version = "3.2.4"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
repository = "https://gitlab.com/asus-linux/asus-nb-ctrl"
homepage = "https://gitlab.com/asus-linux/asus-nb-ctrl"
description = "A daemon app for ASUS GX502 and similar laptops to control missing features"
edition = "2018"
[lib]
name = "daemon"
path = "src/lib.rs"
[[bin]]
name = "asusd"
path = "src/daemon.rs"
[dependencies]
rog_types = { path = "../rog-types" }
rog_dbus = { path = "../rog-dbus" }
rusb = "^0.7"
udev = "^0.6"
# cli and logging
log = "^0.4"
env_logger = "^0.8"
zbus = "^2.0.0-beta.3"
zvariant = "^2.5"
logind-zbus = "*"
# serialisation
serde = "^1.0"
serde_derive = "^1.0"
serde_json = "^1.0"
toml = "^0.5"
# Device control
sysfs-class = "^0.1.2" # used for backlight control and baord ID
rog_fan_curve = { version = "0.1", features = ["serde"] }
# cpu power management
intel-pstate = "^0.2"

View File

@@ -1,137 +0,0 @@
use log::{error, info, warn};
use rog_types::{gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use crate::config_old::*;
use crate::VERSION;
pub static CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/asusd.conf";
#[derive(Deserialize, Serialize)]
pub struct Config {
pub gfx_mode: GfxVendors,
pub gfx_managed: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub power_profiles: BTreeMap<String, Profile>,
}
impl Default for Config {
fn default() -> Self {
let mut pwr = BTreeMap::new();
pwr.insert("normal".into(), Profile::new(0, 100, true, 0, None));
pwr.insert("boost".into(), Profile::new(0, 100, true, 1, None));
pwr.insert("silent".into(), Profile::new(0, 100, true, 2, None));
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: true,
active_profile: "normal".into(),
toggle_profiles: vec!["normal".into(), "boost".into(), "silent".into()],
curr_fan_mode: 0,
bat_charge_limit: 100,
power_profiles: pwr,
}
}
}
impl Config {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load() -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return Config::create_default(&mut file);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<ConfigV317>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV301>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV222>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
} else if let Ok(data) = serde_json::from_str::<ConfigV212>(&buf) {
let config = data.into_current();
config.write();
info!("Updated config version to: {}", VERSION);
return config;
}
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);
}
}
Config::create_default(&mut file)
}
fn create_default(file: &mut File) -> Self {
let config = Config::default();
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string_pretty(&config).unwrap();
file.write_all(json.as_bytes())
.unwrap_or_else(|_| panic!("Could not write {}", CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("File is empty {}", CONFIG_PATH);
} else {
let x: Config = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", CONFIG_PATH));
*self = x;
}
}
}
pub fn read_new() -> Result<Config, Box<dyn std::error::Error>> {
let mut file = OpenOptions::new()
.read(true)
.open(&CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", CONFIG_PATH, err));
let mut buf = String::new();
file.read_to_string(&mut buf)?;
let x: Config = serde_json::from_str(&buf)?;
Ok(x)
}
pub fn write(&self) {
let mut file = File::create(CONFIG_PATH).expect("Couldn't overwrite config");
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
}

View File

@@ -1,148 +0,0 @@
use crate::laptops::LaptopLedData;
use log::{error, info, warn};
use rog_types::aura_modes::{AuraEffect, AuraModeNum, AuraMultiZone, AuraZone, LedBrightness};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf";
#[derive(Deserialize, Serialize)]
pub struct AuraConfigV320 {
pub brightness: u32,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl AuraConfigV320 {
pub(crate) fn into_current(self) -> AuraConfig {
AuraConfig {
brightness: <LedBrightness>::from(self.brightness),
current_mode: self.current_mode,
builtins: self.builtins,
multizone: self.multizone,
}
}
}
#[derive(Deserialize, Serialize)]
pub struct AuraConfig {
pub brightness: LedBrightness,
pub current_mode: AuraModeNum,
pub builtins: BTreeMap<AuraModeNum, AuraEffect>,
pub multizone: Option<AuraMultiZone>,
}
impl Default for AuraConfig {
fn default() -> Self {
AuraConfig {
brightness: LedBrightness::Med,
current_mode: AuraModeNum::Static,
builtins: BTreeMap::new(),
multizone: None,
}
}
}
impl AuraConfig {
/// `load` will attempt to read the config, and panic if the dir is missing
pub fn load(supported_led_modes: &LaptopLedData) -> Self {
let mut file = OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|_| {
panic!(
"The file {} or directory /etc/asusd/ is missing",
AURA_CONFIG_PATH
)
}); // okay to cause panic here
let mut buf = String::new();
if let Ok(read_len) = file.read_to_string(&mut buf) {
if read_len == 0 {
return AuraConfig::create_default(&mut file, &supported_led_modes);
} else {
if let Ok(data) = serde_json::from_str(&buf) {
return data;
} else if let Ok(data) = serde_json::from_str::<AuraConfigV320>(&buf) {
let config = data.into_current();
config.write();
info!("Updated AuraConfig version");
return config;
}
warn!("Could not deserialise {}", AURA_CONFIG_PATH);
panic!("Please remove {} then restart asusd", AURA_CONFIG_PATH);
}
}
AuraConfig::create_default(&mut file, &supported_led_modes)
}
fn create_default(file: &mut File, support_data: &LaptopLedData) -> Self {
// create a default config here
let mut config = AuraConfig::default();
for n in &support_data.standard {
config
.builtins
.insert(*n, AuraEffect::default_with_mode(*n));
}
// Should be okay to unwrap this as is since it is a Default
let json = serde_json::to_string(&config).unwrap();
file.write_all(json.as_bytes())
.unwrap_or_else(|_| panic!("Could not write {}", AURA_CONFIG_PATH));
config
}
pub fn read(&mut self) {
let mut file = OpenOptions::new()
.read(true)
.open(&AURA_CONFIG_PATH)
.unwrap_or_else(|err| panic!("Error reading {}: {}", AURA_CONFIG_PATH, err));
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("File is empty {}", AURA_CONFIG_PATH);
} else {
let x: AuraConfig = serde_json::from_str(&buf)
.unwrap_or_else(|_| panic!("Could not deserialise {}", AURA_CONFIG_PATH));
*self = x;
}
}
}
pub fn write(&self) {
let mut file = File::create(AURA_CONFIG_PATH).expect("Couldn't overwrite config");
let json = serde_json::to_string_pretty(self).expect("Parse config to JSON failed");
file.write_all(json.as_bytes())
.unwrap_or_else(|err| error!("Could not write config: {}", err));
}
/// Multipurpose, will accecpt AuraEffect with zones and put in the correct store
pub fn set_builtin(&mut self, effect: AuraEffect) {
match effect.zone() {
AuraZone::None => {
self.builtins.insert(*effect.mode(), effect);
}
_ => {
if let Some(multi) = self.multizone.as_mut() {
multi.set(effect)
}
}
}
}
pub fn get_multizone(&self, aura_type: AuraModeNum) -> Option<&[AuraEffect; 4]> {
if let Some(multi) = &self.multizone {
if aura_type == AuraModeNum::Static {
return Some(multi.static_());
} else if aura_type == AuraModeNum::Breathe {
return Some(multi.breathe());
}
}
None
}
}

View File

@@ -1,125 +0,0 @@
use rog_types::{aura_modes::AuraEffect, gfx_vendors::GfxVendors, profile::Profile};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeMap;
use crate::config::Config;
/// for parsing old v2.1.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV212 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV212 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v2.2.2 config
#[allow(dead_code)]
#[derive(Deserialize)]
pub(crate) struct ConfigV222 {
gfx_managed: bool,
bat_charge_limit: u8,
active_profile: String,
toggle_profiles: Vec<String>,
power_profiles: BTreeMap<String, Profile>,
power_profile: u8,
kbd_led_brightness: u8,
kbd_backlight_mode: u8,
kbd_backlight_modes: Vec<AuraEffect>,
}
impl ConfigV222 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.power_profile,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v3.0.1 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV301 {
pub gfx_managed: bool,
pub gfx_nv_mode_is_dedicated: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
// TODO: remove power_profile
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
pub kbd_backlight_modes: Vec<AuraEffect>,
pub power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV301 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}
}
/// for parsing old v3.1.7 config
#[derive(Deserialize, Serialize)]
pub(crate) struct ConfigV317 {
pub gfx_mode: GfxVendors,
pub gfx_managed: bool,
pub active_profile: String,
pub toggle_profiles: Vec<String>,
#[serde(skip)]
pub curr_fan_mode: u8,
pub bat_charge_limit: u8,
pub kbd_led_brightness: u8,
pub kbd_backlight_mode: u8,
#[serde(skip)]
pub kbd_backlight_modes: Option<bool>,
pub power_profiles: BTreeMap<String, Profile>,
}
impl ConfigV317 {
pub(crate) fn into_current(self) -> Config {
Config {
gfx_mode: GfxVendors::Hybrid,
gfx_managed: self.gfx_managed,
active_profile: self.active_profile,
toggle_profiles: self.toggle_profiles,
curr_fan_mode: self.curr_fan_mode,
bat_charge_limit: self.bat_charge_limit,
power_profiles: self.power_profiles,
}
}
}

View File

@@ -1,264 +0,0 @@
const INIT_STR: &str = "ASUS Tech.Inc.";
const PACKET_SIZE: usize = 640;
// Only these two packets must be 17 bytes
const DEV_PAGE: u8 = 0x5e;
// These bytes are in [1] position of the array
const WRITE: u8 = 0xc0;
const INIT: u8 = 0xc2;
const SET: u8 = 0xc3;
const APPLY: u8 = 0xc4;
// Used to turn the panel on and off
// The next byte can be 0x03 for "on" and 0x00 for "off"
const ON_OFF: u8 = 0x04;
use log::{error, info, warn};
use rog_types::{
anime_matrix::{
AniMeDataBuffer, AniMeImageBuffer, AniMePacketType, ANIME_PANE1_PREFIX, ANIME_PANE2_PREFIX,
},
error::AuraError,
};
use rusb::{Device, DeviceHandle};
use std::error::Error;
use std::time::Duration;
use zbus::dbus_interface;
use crate::GetSupported;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct AnimeSupportedFunctions(pub bool);
impl GetSupported for CtrlAnimeDisplay {
type A = AnimeSupportedFunctions;
fn get_supported() -> Self::A {
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(0x0b05, 0x193b).is_ok())
}
}
pub struct CtrlAnimeDisplay {
handle: DeviceHandle<rusb::GlobalContext>,
}
//AnimatrixWrite
pub trait Dbus {
/// Write an image 34x56 pixels. Each pixel is 0-255 greyscale.
fn write_image(&self, input: AniMeImageBuffer);
/// Write a direct stream of data
fn write_direct(&self, input: AniMeDataBuffer);
fn set_on_off(&self, status: bool);
fn set_boot_on_off(&self, status: bool);
}
impl crate::ZbusAdd for CtrlAnimeDisplay {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Anime", self)
.map_err(|err| {
warn!("CtrlAnimeDisplay: add_to_server {}", err);
err
})
.ok();
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlAnimeDisplay {
/// Writes a 34x56 image
fn write_image(&self, input: AniMeImageBuffer) {
self.write_image_buffer(input)
.map_or_else(|err| warn!("{}", err), |()| info!("Writing image to Anime"));
}
/// Writes a data stream of length
fn write_direct(&self, input: AniMeDataBuffer) {
self.write_data_buffer(input)
.map_or_else(|err| warn!("{}", err), |()| info!("Writing data to Anime"));
}
fn set_on_off(&self, status: bool) {
let mut buffer = [0u8; PACKET_SIZE];
buffer[0] = DEV_PAGE;
buffer[1] = WRITE;
buffer[2] = ON_OFF;
if status {
buffer[3] = 0x03;
} else {
buffer[3] = 0x00;
}
self.write_bytes(&buffer);
}
fn set_boot_on_off(&self, status: bool) {
let status_str = if status { "on" } else { "off" };
self.do_set_boot(status).map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
);
self.do_apply().map_or_else(
|err| warn!("{}", err),
|()| info!("Turning {} the AniMe at boot/shutdown", status_str),
);
}
}
impl CtrlAnimeDisplay {
#[inline]
pub fn new() -> Result<CtrlAnimeDisplay, Box<dyn Error>> {
// We don't expect this ID to ever change
let device = CtrlAnimeDisplay::get_device(0x0b05, 0x193b)?;
let mut device = device.open()?;
device.reset()?;
device.set_auto_detach_kernel_driver(true).map_err(|err| {
error!("Auto-detach kernel driver failed: {}", err);
err
})?;
device.claim_interface(0).map_err(|err| {
error!("Could not claim device interface: {}", err);
err
})?;
info!("Device has an AniMe Matrix display");
let ctrl = CtrlAnimeDisplay { handle: device };
ctrl.do_initialization()?;
Ok(ctrl)
}
#[inline]
fn get_device(vendor: u16, product: u16) -> Result<Device<rusb::GlobalContext>, rusb::Error> {
for device in rusb::devices()?.iter() {
let device_desc = device.device_descriptor()?;
if device_desc.vendor_id() == vendor && device_desc.product_id() == product {
return Ok(device);
}
}
Err(rusb::Error::NoDevice)
}
/// Should only be used if the bytes you are writing are verified correct
#[inline]
fn write_bytes(&self, message: &[u8]) {
match self.handle.write_control(
0x21, // request_type
0x09, // request
0x35e, // value
0x00, // index
message,
Duration::from_millis(200),
) {
Ok(_) => {}
Err(err) => match err {
rusb::Error::Timeout => {}
_ => error!("Failed to write to led interrupt: {}", err),
},
}
}
#[inline]
fn write_data_buffer(&self, buffer: AniMeDataBuffer) -> Result<(), AuraError> {
let mut image = AniMePacketType::from(buffer);
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
for row in image.iter() {
self.write_bytes(row);
}
self.do_flush()?;
Ok(())
}
/// Write an Animatrix image
///
/// The expected USB input here is *two* Vectors, 640 bytes in length. The two vectors
/// are each one half of the full image write.
///
/// After each write a flush is written, it is assumed that this tells the device to
/// go ahead and display the written bytes
///
/// # Note:
/// The vectors are expected to contain the full sequence of bytes as follows
///
/// - Write pane 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. <led brightness>
/// - Write pane 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
fn write_image_buffer(&self, buffer: AniMeImageBuffer) -> Result<(), AuraError> {
let mut image = AniMePacketType::from(buffer);
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
for row in image.iter() {
self.write_bytes(row);
}
self.do_flush()?;
Ok(())
}
#[inline]
fn do_initialization(&self) -> Result<(), AuraError> {
let mut init = [0; PACKET_SIZE];
init[0] = DEV_PAGE; // This is the USB page we're using throughout
for (idx, byte) in INIT_STR.as_bytes().iter().enumerate() {
init[idx + 1] = *byte
}
self.write_bytes(&init);
// clear the init array and write other init message
for ch in init.iter_mut() {
*ch = 0;
}
init[0] = DEV_PAGE; // write it to be sure?
init[1] = INIT;
self.write_bytes(&init);
Ok(())
}
#[inline]
fn do_flush(&self) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = WRITE;
flush[2] = 0x03;
self.write_bytes(&flush);
Ok(())
}
#[inline]
fn do_set_boot(&self, status: bool) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = SET;
flush[2] = 0x01;
flush[3] = if status { 0x00 } else { 0x80 };
self.write_bytes(&flush);
Ok(())
}
#[inline]
fn do_apply(&self) -> Result<(), AuraError> {
let mut flush = [0; PACKET_SIZE];
flush[0] = DEV_PAGE;
flush[1] = APPLY;
flush[2] = 0x01;
flush[3] = 0x80;
self.write_bytes(&flush);
Ok(())
}
}

View File

@@ -1,124 +0,0 @@
use crate::{config::Config, error::RogError, GetSupported};
//use crate::dbus::DbusEvents;
use log::{info, warn};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::dbus_interface;
static BAT_CHARGE_PATH: &str = "/sys/class/power_supply/BAT0/charge_control_end_threshold";
#[derive(Serialize, Deserialize)]
pub struct ChargeSupportedFunctions {
pub charge_level_set: bool,
}
impl GetSupported for CtrlCharge {
type A = ChargeSupportedFunctions;
fn get_supported() -> Self::A {
ChargeSupportedFunctions {
charge_level_set: CtrlCharge::get_battery_path().is_ok(),
}
}
}
pub struct CtrlCharge {
config: Arc<Mutex<Config>>,
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlCharge {
pub fn set_limit(&mut self, limit: u8) {
if let Ok(mut config) = self.config.try_lock() {
self.set(limit, &mut config)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
self.notify_charge(limit)
.map_err(|err| {
warn!("CtrlCharge: set_limit {}", err);
err
})
.ok();
}
}
pub fn limit(&self) -> i8 {
if let Ok(config) = self.config.try_lock() {
return config.bat_charge_limit as i8;
}
-1
}
#[dbus_interface(signal)]
pub fn notify_charge(&self, limit: u8) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for CtrlCharge {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Charge", self)
.map_err(|err| {
warn!("CtrlCharge: add_to_server {}", err);
err
})
.ok();
}
}
impl crate::Reloadable for CtrlCharge {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.try_lock() {
config.read();
self.set(config.bat_charge_limit, &mut config)?;
}
Ok(())
}
}
impl CtrlCharge {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
CtrlCharge::get_battery_path()?;
Ok(CtrlCharge { config })
}
fn get_battery_path() -> Result<&'static str, RogError> {
if Path::new(BAT_CHARGE_PATH).exists() {
Ok(BAT_CHARGE_PATH)
} else {
Err(RogError::MissingFunction(
"Charge control not available, you may require a v5.8.10 series kernel or newer"
.into(),
))
}
}
pub(super) fn set(&self, limit: u8, config: &mut Config) -> Result<(), RogError> {
if !(20..=100).contains(&limit) {
warn!(
"Unable to set battery charge limit, must be between 20-100: requested {}",
limit
);
}
let mut file = OpenOptions::new()
.write(true)
.open(BAT_CHARGE_PATH)
.map_err(|err| RogError::Path(BAT_CHARGE_PATH.into(), err))?;
file.write_all(limit.to_string().as_bytes())
.map_err(|err| RogError::Write(BAT_CHARGE_PATH.into(), err))?;
info!("Battery charge limit: {}", limit);
config.read();
config.bat_charge_limit = limit;
config.write();
Ok(())
}
}

View File

@@ -1,398 +0,0 @@
use crate::error::RogError;
use crate::{config::Config, GetSupported};
use log::{info, warn};
use rog_types::profile::{FanLevel, Profile, ProfileEvent};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Write;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::{dbus_interface, fdo::Error};
static FAN_TYPE_1_PATH: &str = "/sys/devices/platform/asus-nb-wmi/throttle_thermal_policy";
static FAN_TYPE_2_PATH: &str = "/sys/devices/platform/asus-nb-wmi/fan_boost_mode";
static AMD_BOOST_PATH: &str = "/sys/devices/system/cpu/cpufreq/boost";
pub struct CtrlFanAndCPU {
pub path: &'static str,
config: Arc<Mutex<Config>>,
}
#[derive(Serialize, Deserialize)]
pub struct FanCpuSupportedFunctions {
pub stock_fan_modes: bool,
pub min_max_freq: bool,
pub fan_curve_set: bool,
}
impl GetSupported for CtrlFanAndCPU {
type A = FanCpuSupportedFunctions;
fn get_supported() -> Self::A {
FanCpuSupportedFunctions {
stock_fan_modes: CtrlFanAndCPU::get_fan_path().is_ok(),
min_max_freq: intel_pstate::PState::new().is_ok(),
fan_curve_set: rog_fan_curve::Board::from_board_name().is_some(),
}
}
}
pub struct DbusFanAndCpu {
inner: Arc<Mutex<CtrlFanAndCPU>>,
}
impl DbusFanAndCpu {
pub fn new(inner: Arc<Mutex<CtrlFanAndCPU>>) -> Self {
Self { inner }
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusFanAndCpu {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.handle_profile_event(&event, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
}
/// Fetch the active profile name
fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
cfg.read();
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
/// Fetch the active profile name
fn active_profile_name(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
return Ok(cfg.active_profile.clone());
}
}
Err(Error::Failed(
"Failed to get active profile name".to_string(),
))
}
// TODO: Profile can't implement Type because of Curve
/// Fetch the active profile details
fn profile(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string_pretty(profile) {
return Ok(json);
}
}
}
}
Err(Error::Failed(
"Failed to get active profile details".to_string(),
))
}
/// Fetch all profile data
fn profiles(&mut self) -> zbus::fdo::Result<String> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if let Ok(json) = serde_json::to_string_pretty(&cfg.power_profiles) {
return Ok(json);
}
}
}
Err(Error::Failed(
"Failed to get all profile details".to_string(),
))
}
fn profile_names(&self) -> zbus::fdo::Result<Vec<String>> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
let profile_names = cfg.power_profiles.keys().cloned().collect::<Vec<String>>();
return Ok(profile_names);
}
}
Err(Error::Failed("Failed to get all profile names".to_string()))
}
fn remove(&self, profile: &str) -> zbus::fdo::Result<()> {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
cfg.read();
if !cfg.power_profiles.contains_key(profile) {
return Err(Error::Failed("Invalid profile specified".to_string()));
}
if cfg.power_profiles.keys().len() == 1 {
return Err(Error::Failed("Cannot delete the last profile".to_string()));
}
if cfg.active_profile == *profile {
return Err(Error::Failed(
"Cannot delete the active profile".to_string(),
));
}
cfg.power_profiles.remove(profile);
cfg.write();
return Ok(());
}
}
Err(Error::Failed("Failed to lock configuration".to_string()))
}
#[dbus_interface(signal)]
fn notify_profile(&self, profile: &str) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for DbusFanAndCpu {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Profile", self)
.map_err(|err| {
warn!("DbusFanAndCpu: add_to_server {}", err);
err
})
.ok();
}
}
impl crate::Reloadable for CtrlFanAndCPU {
fn reload(&mut self) -> Result<(), RogError> {
if let Ok(mut config) = self.config.clone().try_lock() {
let profile = config.active_profile.clone();
self.set(&profile, &mut config)?;
// info!(
// "Reloaded fan mode: {:?}",
// FanLevel::from(config.power_profile)
// );
}
Ok(())
}
}
impl CtrlFanAndCPU {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
let path = CtrlFanAndCPU::get_fan_path()?;
info!("Device has thermal throttle control");
Ok(CtrlFanAndCPU { path, config })
}
fn get_fan_path() -> Result<&'static str, RogError> {
if Path::new(FAN_TYPE_1_PATH).exists() {
Ok(FAN_TYPE_1_PATH)
} else if Path::new(FAN_TYPE_2_PATH).exists() {
Ok(FAN_TYPE_2_PATH)
} else {
Err(RogError::MissingFunction(
"Fan mode not available, you may require a v5.8.10 series kernel or newer".into(),
))
}
}
/// Toggle to next profile in list
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> {
config.read();
let mut i = config
.toggle_profiles
.iter()
.position(|x| x == &config.active_profile)
.map(|i| i + 1)
.unwrap_or(0);
if i >= config.toggle_profiles.len() {
i = 0;
}
let new_profile = config
.toggle_profiles
.get(i)
.unwrap_or(&config.active_profile)
.clone();
self.set(&new_profile, config)?;
info!("Profile was changed: {}", &new_profile);
Ok(())
}
fn set_fan_mode(&mut self, preset: u8, config: &mut Config) -> Result<(), RogError> {
let mode = config.active_profile.clone();
let mut fan_ctrl = OpenOptions::new()
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
config.read();
let mut mode_config = config
.power_profiles
.get_mut(&mode)
.ok_or_else(|| RogError::MissingProfile(mode.clone()))?;
config.curr_fan_mode = preset;
mode_config.fan_preset = preset;
config.write();
fan_ctrl
.write_all(format!("{}\n", preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
info!("Fan mode set to: {:?}", FanLevel::from(preset));
Ok(())
}
fn handle_profile_event(
&mut self,
event: &ProfileEvent,
config: &mut Config,
) -> Result<(), RogError> {
match event {
ProfileEvent::Toggle => self.do_next_profile(config)?,
ProfileEvent::ChangeMode(mode) => {
self.set_fan_mode(*mode, config)?;
let mode = config.active_profile.clone();
self.set_pstate_for_fan_mode(&mode, config)?;
self.set_fan_curve_for_fan_mode(&mode, config)?;
}
ProfileEvent::Cli(command) => {
let profile_key = match command.profile.as_ref() {
Some(k) => k.clone(),
None => config.active_profile.clone(),
};
let mut profile = if command.create {
config
.power_profiles
.entry(profile_key.clone())
.or_insert_with(Profile::default)
} else {
config
.power_profiles
.get_mut(&profile_key)
.ok_or_else(|| RogError::MissingProfile(profile_key.clone()))?
};
if command.turbo.is_some() {
profile.turbo = command.turbo.unwrap();
}
if let Some(min_perc) = command.min_percentage {
profile.min_percentage = min_perc;
}
if let Some(max_perc) = command.max_percentage {
profile.max_percentage = max_perc;
}
if let Some(ref preset) = command.fan_preset {
profile.fan_preset = preset.into();
}
if let Some(ref curve) = command.curve {
profile.fan_curve = Some(curve.clone());
}
self.set(&profile_key, config)?;
}
}
Ok(())
}
fn set(&mut self, profile: &str, config: &mut Config) -> Result<(), RogError> {
let mode_config = config
.power_profiles
.get(profile)
.ok_or_else(|| RogError::MissingProfile(profile.into()))?;
let mut fan_ctrl = OpenOptions::new()
.write(true)
.open(self.path)
.map_err(|err| RogError::Path(self.path.into(), err))?;
config.curr_fan_mode = mode_config.fan_preset;
fan_ctrl
.write_all(format!("{}\n", mode_config.fan_preset).as_bytes())
.map_err(|err| RogError::Write(self.path.into(), err))?;
self.set_pstate_for_fan_mode(profile, config)?;
self.set_fan_curve_for_fan_mode(profile, config)?;
config.active_profile = profile.into();
config.write();
Ok(())
}
fn set_pstate_for_fan_mode(&self, mode: &str, config: &mut Config) -> Result<(), RogError> {
info!("Setting pstate");
let mode_config = config
.power_profiles
.get(mode)
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
// Set CPU pstate
if let Ok(pstate) = intel_pstate::PState::new() {
pstate.set_min_perf_pct(mode_config.min_percentage)?;
pstate.set_max_perf_pct(mode_config.max_percentage)?;
pstate.set_no_turbo(!mode_config.turbo)?;
info!(
"Intel CPU Power: min: {}%, max: {}%, turbo: {}",
mode_config.min_percentage, mode_config.max_percentage, mode_config.turbo
);
} else {
info!("Setting pstate for AMD CPU");
// must be AMD CPU
let mut file = OpenOptions::new()
.write(true)
.open(AMD_BOOST_PATH)
.map_err(|err| RogError::Path(self.path.into(), err))?;
let boost = if mode_config.turbo { "1" } else { "0" }; // opposite of Intel
file.write_all(boost.as_bytes())
.map_err(|err| RogError::Write(AMD_BOOST_PATH.into(), err))?;
info!("AMD CPU Turbo: {}", boost);
}
Ok(())
}
fn set_fan_curve_for_fan_mode(&self, mode: &str, config: &Config) -> Result<(), RogError> {
let mode_config = &config
.power_profiles
.get(mode)
.ok_or_else(|| RogError::MissingProfile(mode.into()))?;
if let Some(ref curve) = mode_config.fan_curve {
use rog_fan_curve::{Board, Fan};
if let Some(board) = Board::from_board_name() {
curve.apply(board, Fan::Cpu)?;
curve.apply(board, Fan::Gpu)?;
} else {
warn!("Fan curve unsupported on this board.")
}
}
Ok(())
}
}

View File

@@ -1,52 +0,0 @@
use std::fmt;
use std::{error, process::ExitStatus};
use crate::error::RogError;
#[derive(Debug)]
pub enum GfxError {
ParseVendor,
Bus(String, std::io::Error),
DisplayManagerAction(String, ExitStatus),
DisplayManagerTimeout(String),
GsyncModeActive,
VfioBuiltin,
MissingModule(String),
Modprobe(String),
Command(String, std::io::Error),
}
impl fmt::Display for GfxError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
GfxError::ParseVendor => write!(f, "Could not parse vendor name"),
GfxError::Bus(func, error) => write!(f, "Bus error: {}: {}", func, error),
GfxError::DisplayManagerAction(action, status) => {
write!(f, "Display-manager action {} failed: {}", action, status)
}
GfxError::DisplayManagerTimeout(state) => {
write!(f, "Timed out waiting for display-manager {} state", state)
}
GfxError::GsyncModeActive => write!(
f,
"Can not switch gfx modes when dedicated/G-Sync mode is active"
),
GfxError::VfioBuiltin => write!(
f,
"Can not switch to vfio mode if the modules are built in to kernel"
),
GfxError::MissingModule(m) => write!(f, "The module {} is missing", m),
GfxError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
GfxError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
}
}
}
impl error::Error for GfxError {}
impl From<GfxError> for RogError {
fn from(err: GfxError) -> Self {
RogError::GfxSwitching(err)
}
}

View File

@@ -1,639 +0,0 @@
use ctrl_gfx::error::GfxError;
use ctrl_gfx::*;
use ctrl_rog_bios::CtrlRogBios;
use log::{error, info, warn};
use logind_zbus::{
types::{SessionClass, SessionInfo, SessionState, SessionType},
ManagerProxy, SessionProxy,
};
use rog_types::gfx_vendors::{GfxRequiredUserAction, GfxVendors};
use std::sync::mpsc;
use std::{io::Write, ops::Add, path::Path, time::Instant};
use std::{iter::FromIterator, thread::JoinHandle};
use std::{process::Command, thread::sleep, time::Duration};
use std::{sync::Arc, sync::Mutex};
use sysfs_class::{PciDevice, SysClass};
use system::{GraphicsDevice, PciBus};
use zbus::{dbus_interface, Connection};
use crate::*;
const THREAD_TIMEOUT_MSG: &str = "GFX: thread time exceeded 3 minutes, exiting";
pub struct CtrlGraphics {
bus: PciBus,
_amd: Vec<GraphicsDevice>,
_intel: Vec<GraphicsDevice>,
nvidia: Vec<GraphicsDevice>,
#[allow(dead_code)]
other: Vec<GraphicsDevice>,
config: Arc<Mutex<Config>>,
thread_kill: Arc<Mutex<Option<mpsc::Sender<bool>>>>,
}
trait Dbus {
fn vendor(&self) -> zbus::fdo::Result<GfxVendors>;
fn power(&self) -> String;
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction>;
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()>;
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()>;
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl Dbus for CtrlGraphics {
fn vendor(&self) -> zbus::fdo::Result<GfxVendors> {
self.get_gfx_mode().map_err(|err| {
error!("GFX: {}", err);
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
})
}
fn power(&self) -> String {
Self::get_runtime_status().unwrap_or_else(|err| format!("Get power status failed: {}", err))
}
fn set_vendor(&mut self, vendor: GfxVendors) -> zbus::fdo::Result<GfxRequiredUserAction> {
info!("GFX: Switching gfx mode to {}", <&str>::from(vendor));
let msg = self.set_gfx_config(vendor).map_err(|err| {
error!("GFX: {}", err);
zbus::fdo::Error::Failed(format!("GFX fail: {}", err))
})?;
self.notify_gfx(&vendor)
.unwrap_or_else(|err| warn!("GFX: {}", err));
self.notify_action(&msg)
.unwrap_or_else(|err| warn!("GFX: {}", err));
Ok(msg)
}
#[dbus_interface(signal)]
fn notify_gfx(&self, vendor: &GfxVendors) -> zbus::Result<()> {}
#[dbus_interface(signal)]
fn notify_action(&self, action: &GfxRequiredUserAction) -> zbus::Result<()> {}
}
impl ZbusAdd for CtrlGraphics {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Gfx", self)
.map_err(|err| {
warn!("GFX: CtrlGraphics: add_to_server {}", err);
err
})
.ok();
}
}
impl Reloadable for CtrlGraphics {
fn reload(&mut self) -> Result<(), RogError> {
self.auto_power()?;
info!("GFX: Reloaded gfx mode: {:?}", self.get_gfx_mode()?);
Ok(())
}
}
impl CtrlGraphics {
pub fn new(config: Arc<Mutex<Config>>) -> std::io::Result<CtrlGraphics> {
let bus = PciBus::new()?;
info!("GFX: Rescanning PCI bus");
bus.rescan()?;
let devs = PciDevice::all()?;
let functions = |parent: &PciDevice| -> Vec<PciDevice> {
let mut functions = Vec::new();
if let Some(parent_slot) = parent.id().split('.').next() {
for func in devs.iter() {
if let Some(func_slot) = func.id().split('.').next() {
if func_slot == parent_slot {
info!("GFX: {}: Function for {}", func.id(), parent.id());
functions.push(func.clone());
}
}
}
}
functions
};
let mut amd = Vec::new();
let mut intel = Vec::new();
let mut nvidia = Vec::new();
let mut other = Vec::new();
for dev in devs.iter() {
let c = dev.class()?;
if 0x03 == (c >> 16) & 0xFF {
match dev.vendor()? {
0x1002 => {
info!("GFX: {}: AMD graphics", dev.id());
amd.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x10DE => {
info!("GFX: {}: NVIDIA graphics", dev.id());
nvidia.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
0x8086 => {
info!("GFX: {}: Intel graphics", dev.id());
intel.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
vendor => {
info!("GFX: {}: Other({:X}) graphics", dev.id(), vendor);
other.push(GraphicsDevice::new(dev.id().to_owned(), functions(&dev)));
}
}
}
}
Ok(CtrlGraphics {
bus,
_amd: amd,
_intel: intel,
nvidia,
other,
config,
thread_kill: Arc::new(Mutex::new(None)),
})
}
pub fn bus(&self) -> PciBus {
self.bus.clone()
}
pub fn devices(&self) -> Vec<GraphicsDevice> {
self.nvidia.clone()
}
/// Save the selected `Vendor` mode to config
fn save_gfx_mode(vendor: GfxVendors, config: Arc<Mutex<Config>>) {
if let Ok(mut config) = config.lock() {
config.gfx_mode = vendor;
config.write();
}
}
/// Associated method to get which vendor mode is set
pub fn get_gfx_mode(&self) -> Result<GfxVendors, RogError> {
if let Ok(config) = self.config.lock() {
return Ok(config.gfx_mode);
}
// TODO: Error here
Ok(GfxVendors::Hybrid)
}
fn get_runtime_status() -> Result<String, RogError> {
const PATH: &str = "/sys/bus/pci/devices/0000:01:00.0/power/runtime_status";
let buf = std::fs::read_to_string(PATH).map_err(|err| RogError::Read(PATH.into(), err))?;
Ok(buf)
}
/// Some systems have a fallback service to load nouveau if nvidia fails
fn toggle_fallback_service(vendor: GfxVendors) -> Result<(), RogError> {
let action = if vendor == GfxVendors::Nvidia {
info!("GFX: Enabling nvidia-fallback.service");
"enable"
} else {
info!("GFX: Disabling nvidia-fallback.service");
"disable"
};
let status = Command::new("systemctl")
.arg(action)
.arg("nvidia-fallback.service")
.status()
.map_err(|err| RogError::Command("systemctl".into(), err))?;
if !status.success() {
// Error is ignored in case this service is removed
warn!(
"systemctl: {} (ignore warning if service does not exist!)",
status
);
}
Ok(())
}
/// Write the appropriate xorg config for the chosen mode
fn write_xorg_conf(vendor: GfxVendors) -> Result<(), RogError> {
let text = if vendor == GfxVendors::Nvidia {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_NVIDIA, PRIMARY_GPU_END].concat()
} else {
[PRIMARY_GPU_BEGIN, PRIMARY_GPU_END].concat()
};
if !Path::new(XORG_PATH).exists() {
std::fs::create_dir(XORG_PATH).map_err(|err| RogError::Write(XORG_PATH.into(), err))?;
}
let file = XORG_PATH.to_string().add(XORG_FILE);
info!("GFX: Writing {}", file);
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(&file)
.map_err(|err| RogError::Write(file, err))?;
file.write_all(&text)
.and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
Ok(())
}
/// Creates the full modprobe.conf required for vfio pass-through
fn get_vfio_conf(devices: &[GraphicsDevice]) -> Vec<u8> {
let mut vifo = MODPROBE_VFIO.to_vec();
for (d_count, dev) in devices.iter().enumerate() {
for (f_count, func) in dev.functions().iter().enumerate() {
let vendor = func.vendor().unwrap();
let device = func.device().unwrap();
unsafe {
vifo.append(format!("{:x}", vendor).as_mut_vec());
}
vifo.append(&mut vec![b':']);
unsafe {
vifo.append(format!("{:x}", device).as_mut_vec());
}
if f_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
if d_count < dev.functions().len() - 1 {
vifo.append(&mut vec![b',']);
}
}
let mut conf = MODPROBE_INTEGRATED.to_vec();
conf.append(&mut vifo);
conf
}
fn write_modprobe_conf(vendor: GfxVendors, devices: &[GraphicsDevice]) -> Result<(), RogError> {
info!("GFX: Writing {}", MODPROBE_PATH);
let content = match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => MODPROBE_BASE.to_vec(),
GfxVendors::Vfio => Self::get_vfio_conf(devices),
// GfxVendors::Compute => {}
GfxVendors::Integrated => MODPROBE_INTEGRATED.to_vec(),
};
let mut file = std::fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.open(MODPROBE_PATH)
.map_err(|err| RogError::Path(MODPROBE_PATH.into(), err))?;
file.write_all(&content)
.and_then(|_| file.sync_all())
.map_err(|err| RogError::Write(MODPROBE_PATH.into(), err))?;
Ok(())
}
fn unbind_remove_nvidia(devices: &[GraphicsDevice]) -> Result<(), RogError> {
// Unbind NVIDIA graphics devices and their functions
let unbinds = devices.iter().map(|dev| dev.unbind());
// Remove NVIDIA graphics devices and their functions
let removes = devices.iter().map(|dev| dev.remove());
Result::from_iter(unbinds.chain(removes))
.map_err(|err| RogError::Command("device unbind error".into(), err))
}
fn unbind_only(devices: &[GraphicsDevice]) -> Result<(), RogError> {
let unbinds = devices.iter().map(|dev| dev.unbind());
Result::from_iter(unbinds)
.map_err(|err| RogError::Command("device unbind error".into(), err))
}
fn do_driver_action(driver: &str, action: &str) -> Result<(), GfxError> {
let mut cmd = Command::new(action);
cmd.arg(driver);
let mut count = 0;
const MAX_TRIES: i32 = 6;
loop {
if count > MAX_TRIES {
let msg = format!("{} {} failed for unknown reason", action, driver);
error!("GFX: {}", msg);
return Ok(()); //Err(RogError::Modprobe(msg));
}
let output = cmd
.output()
.map_err(|err| GfxError::Command(format!("{:?}", cmd), err))?;
if !output.status.success() {
if output
.stderr
.ends_with("is not currently loaded\n".as_bytes())
{
return Ok(());
}
if output.stderr.ends_with("is builtin.\n".as_bytes()) {
return Err(GfxError::VfioBuiltin);
}
if output.stderr.ends_with("Permission denied\n".as_bytes()) {
warn!(
"{} {} failed: {:?}",
action,
driver,
String::from_utf8_lossy(&output.stderr)
);
warn!("GFX: It may be safe to ignore the above error, run `lsmod |grep {}` to confirm modules loaded", driver);
return Ok(());
}
if String::from_utf8_lossy(&output.stderr)
.contains(&format!("Module {} not found", driver))
{
return Err(GfxError::MissingModule(driver.into()));
}
if count >= MAX_TRIES {
let msg = format!(
"{} {} failed: {:?}",
action,
driver,
String::from_utf8_lossy(&output.stderr)
);
return Err(GfxError::Modprobe(msg));
}
} else if output.status.success() {
return Ok(());
}
count += 1;
std::thread::sleep(std::time::Duration::from_millis(50));
}
}
fn do_display_manager_action(action: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg(action);
cmd.arg(DISPLAY_MANAGER);
let status = cmd
.status()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if !status.success() {
let msg = format!(
"systemctl {} {} failed: {:?}",
action, DISPLAY_MANAGER, status
);
return Err(GfxError::DisplayManagerAction(msg, status).into());
}
Ok(())
}
fn wait_display_manager_state(state: &str) -> Result<(), RogError> {
let mut cmd = Command::new("systemctl");
cmd.arg("is-active");
cmd.arg(DISPLAY_MANAGER);
let mut count = 0;
while count <= 5 {
let output = cmd
.output()
.map_err(|err| RogError::Command(format!("{:?}", cmd), err))?;
if output.stdout.starts_with(state.as_bytes()) {
return Ok(());
}
std::thread::sleep(std::time::Duration::from_millis(500));
count += 1;
}
Err(GfxError::DisplayManagerTimeout(state.into()).into())
}
/// Determine if we need to logout/thread. Integrated<->Vfio mode does not
/// require logout.
fn logout_required(&self, vendor: GfxVendors) -> GfxRequiredUserAction {
if let Ok(config) = self.config.lock() {
let current = config.gfx_mode;
if matches!(current, GfxVendors::Integrated | GfxVendors::Vfio)
&& matches!(vendor, GfxVendors::Integrated | GfxVendors::Vfio)
{
return GfxRequiredUserAction::None;
}
}
GfxRequiredUserAction::Logout
}
/// Write the config changes and add/remove drivers and devices depending
/// on selected mode:
///
/// Tasks:
/// - write xorg config
/// - write modprobe config
/// - rescan for devices
/// + add drivers
/// + or remove drivers and devices
///
/// The daemon needs direct access to this function when it detects that the
pub fn do_vendor_tasks(
vendor: GfxVendors,
devices: &[GraphicsDevice],
bus: &PciBus,
) -> Result<(), RogError> {
// Rescan before doing remove or add drivers
bus.rescan()?;
//
Self::write_xorg_conf(vendor)?;
// Write different modprobe to enable boot control to work
Self::write_modprobe_conf(vendor, devices)?;
match vendor {
GfxVendors::Nvidia | GfxVendors::Hybrid | GfxVendors::Compute => {
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "modprobe")?;
}
}
GfxVendors::Vfio => {
Self::do_driver_action("nouveau", "rmmod")?;
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
Self::unbind_only(&devices)?;
Self::do_driver_action("vfio-pci", "modprobe")?;
}
GfxVendors::Integrated => {
Self::do_driver_action("nouveau", "rmmod")?;
for driver in VFIO_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod").or_else(|err| {
if matches!(err, GfxError::VfioBuiltin) {
warn!("{}", err);
return Ok(());
}
Err(err)
})?;
}
for driver in NVIDIA_DRIVERS.iter() {
Self::do_driver_action(driver, "rmmod")?;
}
Self::unbind_remove_nvidia(&devices)?;
}
}
Ok(())
}
/// Check if the user has any graphical uiser sessions that are active or online
fn graphical_user_sessions_exist(
connection: &Connection,
sessions: &[SessionInfo],
) -> Result<bool, RogError> {
for session in sessions {
let session_proxy = SessionProxy::new(&connection, session)?;
if session_proxy.get_class()? == SessionClass::User {
match session_proxy.get_type()? {
SessionType::X11 | SessionType::Wayland | SessionType::MIR => {
match session_proxy.get_state()? {
SessionState::Online | SessionState::Active => return Ok(true),
SessionState::Closing | SessionState::Invalid => {}
}
}
_ => {}
}
}
}
Ok(false)
}
/// Spools until all user sessions are ended then switches to requested mode
fn fire_starter(
vendor: GfxVendors,
devices: Vec<GraphicsDevice>,
bus: PciBus,
thread_stop: mpsc::Receiver<bool>,
config: Arc<Mutex<Config>>,
) -> Result<String, RogError> {
info!("GFX: display-manager thread started");
const SLEEP_PERIOD: Duration = Duration::from_millis(100);
let start_time = Instant::now();
let connection = Connection::new_system()?;
let manager = ManagerProxy::new(&connection)?;
let mut sessions = manager.list_sessions()?;
loop {
let tmp = manager.list_sessions()?;
if !tmp.iter().eq(&sessions) {
info!("GFX thread: Sessions list changed");
sessions = tmp;
}
if !Self::graphical_user_sessions_exist(&connection, &sessions)? {
break;
}
if let Ok(stop) = thread_stop.try_recv() {
if stop {
return Ok("Graphics mode change was cancelled".into());
}
}
// exit if 3 minutes pass
if Instant::now().duration_since(start_time).as_secs() > 180 {
warn!("{}", THREAD_TIMEOUT_MSG);
return Ok(THREAD_TIMEOUT_MSG.into());
}
// Don't spin at max speed
sleep(SLEEP_PERIOD);
}
info!("GFX thread: all graphical user sessions ended, continuing");
Self::do_display_manager_action("stop")?;
Self::wait_display_manager_state("inactive")?;
Self::do_vendor_tasks(vendor, &devices, &bus)?;
Self::do_display_manager_action("restart")?;
// Save selected mode in case of reboot
Self::save_gfx_mode(vendor, config);
info!("GFX thread: display-manager started");
let v: &str = vendor.into();
info!("GFX thread: Graphics mode changed to {} successfully", v);
Ok(format!("Graphics mode changed to {} successfully", v))
}
/// Before starting a new thread the old one *must* be cancelled
fn cancel_thread(&self) {
if let Ok(lock) = self.thread_kill.lock() {
if let Some(tx) = lock.as_ref() {
// Cancel the running thread
info!("GFX: Cancelling previous thread");
tx.send(true)
.map_err(|err| {
warn!("GFX thread: {}", err);
})
.ok();
}
}
}
/// The thread is used only in cases where a logout is required
fn setup_thread(&mut self, vendor: GfxVendors) {
let config = self.config.clone();
let devices = self.nvidia.clone();
let bus = self.bus.clone();
let (tx, rx) = mpsc::channel();
if let Ok(mut lock) = self.thread_kill.lock() {
*lock = Some(tx);
}
let killer = self.thread_kill.clone();
let _join: JoinHandle<()> = std::thread::spawn(move || {
Self::fire_starter(vendor, devices, bus, rx, config)
.map_err(|err| {
error!("GFX: {}", err);
})
.ok();
// clear the tx/rx when done
if let Ok(mut lock) = killer.try_lock() {
*lock = None;
}
});
}
/// Initiates a mode change by starting a thread that will wait until all
/// graphical sessions are exited before performing the tasks required
/// to switch modes.
///
/// For manually calling (not on boot/startup) via dbus
pub fn set_gfx_config(
&mut self,
vendor: GfxVendors,
) -> Result<GfxRequiredUserAction, RogError> {
if let Ok(gsync) = CtrlRogBios::get_gfx_mode() {
if gsync == 1 {
return Err(GfxError::GsyncModeActive.into());
}
}
// Must always cancel any thread running
self.cancel_thread();
// determine which method we need here
let action_required = self.logout_required(vendor);
if matches!(action_required, GfxRequiredUserAction::Logout) {
// Yeah need the thread to check if all users are logged out
info!("GFX: mode change requires a logout to complete");
self.setup_thread(vendor);
} else {
// Okay cool, we can switch on/off vfio
info!("GFX: mode change does not require logout");
let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
info!("GFX: Graphics mode changed to {}", <&str>::from(vendor));
}
// TODO: undo if failed? Save last mode, catch errors...
Ok(action_required)
}
/// Used only on boot to set correct mode
fn auto_power(&mut self) -> Result<(), RogError> {
let vendor = self.get_gfx_mode()?;
let devices = self.nvidia.clone();
let bus = self.bus.clone();
Self::do_vendor_tasks(vendor, &devices, &bus)?;
Self::toggle_fallback_service(vendor)?;
Ok(())
}
}

View File

@@ -1,57 +0,0 @@
pub mod error;
pub mod gfx;
pub mod system;
const NVIDIA_DRIVERS: [&str; 4] = ["nvidia_drm", "nvidia_modeset", "nvidia_uvm", "nvidia"];
const VFIO_DRIVERS: [&str; 5] = [
"vfio-pci",
"vfio_iommu_type1",
"vfio_virqfd",
"vfio_mdev",
"vfio",
];
const DISPLAY_MANAGER: &str = "display-manager.service";
const MODPROBE_PATH: &str = "/etc/modprobe.d/asusd.conf";
static MODPROBE_BASE: &[u8] = br#"# Automatically generated by asusd
# If you have issues with i2c_nvidia_gpu, copy the 2 lines below to a
# new blacklist file and uncomment
#blacklist i2c_nvidia_gpu
#alias i2c_nvidia_gpu off
blacklist nouveau
alias nouveau off
options nvidia NVreg_DynamicPowerManagement=0x02
options nvidia-drm modeset=1
"#;
static MODPROBE_INTEGRATED: &[u8] = br#"# Automatically generated by asusd
blacklist i2c_nvidia_gpu
blacklist nvidia
blacklist nvidia-drm
blacklist nvidia-modeset
blacklist nouveau
alias nouveau off
"#;
static MODPROBE_VFIO: &[u8] = br#"options vfio-pci ids="#;
const XORG_FILE: &str = "90-nvidia-primary.conf";
const XORG_PATH: &str = "/etc/X11/xorg.conf.d/";
static PRIMARY_GPU_BEGIN: &[u8] = br#"# Automatically generated by asusd
Section "OutputClass"
Identifier "nvidia"
MatchDriver "nvidia-drm"
Driver "nvidia"
Option "AllowEmptyInitialConfiguration" "true""#;
static PRIMARY_GPU_NVIDIA: &[u8] = br#"
Option "PrimaryGPU" "true""#;
static PRIMARY_GPU_END: &[u8] = br#"
EndSection"#;

View File

@@ -1,160 +0,0 @@
use log::{error, info, warn};
use std::fs::read_to_string;
use std::{fs::write, io, path::PathBuf};
use sysfs_class::{PciDevice, SysClass};
pub struct Module {
pub name: String,
}
impl Module {
fn parse(line: &str) -> io::Result<Module> {
let mut parts = line.split(' ');
let name = parts
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "module name not found"))?;
Ok(Module {
name: name.to_string(),
})
}
pub fn all() -> io::Result<Vec<Module>> {
let mut modules = Vec::new();
let data = read_to_string("/proc/modules")?;
for line in data.lines() {
let module = Module::parse(line)?;
modules.push(module);
}
Ok(modules)
}
}
#[derive(Clone)]
pub struct PciBus {
path: PathBuf,
}
impl PciBus {
pub fn new() -> io::Result<PciBus> {
let path = PathBuf::from("/sys/bus/pci");
if path.is_dir() {
Ok(PciBus { path })
} else {
Err(io::Error::new(
io::ErrorKind::NotFound,
"pci directory not found",
))
}
}
/// Will rescan the device tree, which adds all removed devices back
pub fn rescan(&self) -> io::Result<()> {
write(self.path.join("rescan"), "1")
}
}
#[derive(Clone)]
pub struct GraphicsDevice {
_id: String,
functions: Vec<PciDevice>,
}
impl GraphicsDevice {
pub fn new(id: String, functions: Vec<PciDevice>) -> GraphicsDevice {
GraphicsDevice { _id: id, functions }
}
pub fn exists(&self) -> bool {
self.functions.iter().any(|func| func.path().exists())
}
pub fn functions(&self) -> &[PciDevice] {
&self.functions
}
pub fn unbind(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() {
if func.path().exists() {
match func.driver() {
Ok(driver) => {
info!("{}: Unbinding {}", driver.id(), func.id());
unsafe {
driver.unbind(&func).map_err(|err| {
error!("gfx unbind: {}", err);
err
})?;
}
}
Err(err) => match err.kind() {
io::ErrorKind::NotFound => (),
_ => {
error!("gfx driver: {:?}, {}", func.path(), err);
return Err(err);
}
},
}
}
}
Ok(())
}
pub fn rebind(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() {
if func.path().exists() {
match func.driver() {
Ok(driver) => {
info!("{}: Binding {}", driver.id(), func.id());
unsafe {
driver.bind(&func).map_err(|err| {
error!("gfx bind: {}", err);
err
})?;
}
}
Err(err) => match err.kind() {
io::ErrorKind::NotFound => (),
_ => {
error!("gfx driver: {:?}, {}", func.path(), err);
return Err(err);
}
},
}
}
}
Ok(())
}
pub fn remove(&self) -> Result<(), std::io::Error> {
for func in self.functions.iter() {
if func.path().exists() {
match func.driver() {
Ok(driver) => {
error!("{}: in use by {}", func.id(), driver.id());
}
Err(why) => match why.kind() {
std::io::ErrorKind::NotFound => {
info!("{}: Removing", func.id());
unsafe {
// ignore errors and carry on
if let Err(err) = func.remove() {
error!("gfx remove: {}", err);
}
}
}
_ => {
error!("Remove device failed");
}
},
}
} else {
warn!("{}: Already removed", func.id());
}
}
info!("Removed all gfx devices");
Ok(())
}
}

View File

@@ -1,468 +0,0 @@
// Only these two packets must be 17 bytes
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness";
use crate::{
config_aura::AuraConfig,
error::RogError,
laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES},
};
use log::{error, info, warn};
use rog_types::{
aura_modes::{AuraEffect, AuraModeNum, LedBrightness},
LED_MSG_LEN,
};
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::dbus_interface;
use crate::GetSupported;
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct LedSupportedFunctions {
pub brightness_set: bool,
pub stock_led_modes: Option<Vec<AuraModeNum>>,
pub multizone_led_mode: bool,
pub per_key_led_mode: bool,
}
impl GetSupported for CtrlKbdBacklight {
type A = LedSupportedFunctions;
fn get_supported() -> Self::A {
// let mode = <&str>::from(&<AuraModes>::from(*mode));
let multizone_led_mode = false;
let per_key_led_mode = false;
let laptop = LaptopLedData::get_data();
let stock_led_modes = if laptop.standard.is_empty() {
None
} else {
Some(laptop.standard)
};
LedSupportedFunctions {
brightness_set: CtrlKbdBacklight::get_kbd_bright_path().is_some(),
stock_led_modes,
multizone_led_mode,
per_key_led_mode,
}
}
}
pub struct CtrlKbdBacklight {
led_node: Option<String>,
pub bright_node: String,
supported_modes: LaptopLedData,
flip_effect_write: bool,
config: AuraConfig,
}
pub struct DbusKbdBacklight {
inner: Arc<Mutex<CtrlKbdBacklight>>,
}
impl DbusKbdBacklight {
pub fn new(inner: Arc<Mutex<CtrlKbdBacklight>>) -> Self {
Self { inner }
}
}
trait Dbus {
fn set_led(&mut self, data: String);
fn ledmode(&self) -> String;
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
impl crate::ZbusAdd for DbusKbdBacklight {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Led", self)
.map_err(|err| {
error!("DbusKbdBacklight: add_to_server {}", err);
})
.ok();
}
}
/// The main interface for changing, reading, or notfying signals
///
/// LED commands are split between Brightness, Modes, Per-Key
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusKbdBacklight {
fn set_brightness(&mut self, brightness: LedBrightness) {
if let Ok(ctrl) = self.inner.try_lock() {
ctrl.set_brightness(brightness)
.map_err(|err| warn!("{}", err))
.ok();
}
}
fn set_led_mode(&mut self, effect: AuraEffect) {
if let Ok(mut ctrl) = self.inner.try_lock() {
let mode_name = effect.mode_name();
match ctrl.do_command(effect) {
Ok(_) => {
self.notify_led(&mode_name).ok();
}
Err(err) => {
warn!("{}", err);
}
}
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.toggle_mode(false)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
ctrl.toggle_mode(true)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
self.notify_led(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
/// Return the current mode data
#[dbus_interface(property)]
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Some(mode) = ctrl.config.builtins.get(&ctrl.config.current_mode) {
if let Ok(json) = serde_json::to_string(&mode) {
return json;
}
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
#[dbus_interface(property)]
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(json) = serde_json::to_string(&ctrl.config.builtins) {
return json;
}
}
warn!("SetKeyBacklight could not deserialise");
"SetKeyBacklight could not serialise".to_string()
}
/// Return the current LED brightness
#[dbus_interface(property)]
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
return ctrl.get_brightness().map(|n| n as i8).unwrap_or(-1);
}
warn!("SetKeyBacklight could not serialise");
-1
}
#[dbus_interface(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
impl crate::Reloadable for CtrlKbdBacklight {
fn reload(&mut self) -> Result<(), RogError> {
// set current mode (if any)
if self.supported_modes.standard.len() > 1 {
let current_mode = self.config.current_mode;
if self.supported_modes.standard.contains(&(current_mode)) {
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
} else {
warn!(
"An unsupported mode was set: {}, reset to first mode available",
<&str>::from(&self.config.current_mode)
);
self.config.builtins.remove(&current_mode);
self.config.current_mode = AuraModeNum::Static;
// TODO: do a recursive call with a boxed dyn future later
let mode = self
.config
.builtins
.get(&current_mode)
.ok_or(RogError::NotSupported)?
.to_owned();
self.write_mode(&mode)?;
info!("Reloaded last used mode");
}
}
// Reload brightness
let bright = self.config.brightness;
self.set_brightness(bright)?;
info!("Reloaded last used brightness");
Ok(())
}
}
impl crate::CtrlTask for CtrlKbdBacklight {
fn do_task(&mut self) -> Result<(), RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
if let Some(num) = char::from(buf[0]).to_digit(10) {
if self.config.brightness != num.into() {
self.config.read();
self.config.brightness = num.into();
self.config.write();
}
return Ok(());
}
Err(RogError::ParseLED)
}
}
impl CtrlKbdBacklight {
#[inline]
pub fn new(supported_modes: LaptopLedData, config: AuraConfig) -> Result<Self, RogError> {
// TODO: return error if *all* nodes are None
let mut led_node = None;
for prod in ASUS_KEYBOARD_DEVICES.iter() {
match Self::find_led_node(prod) {
Ok(node) => {
led_node = Some(node);
break;
}
Err(err) => warn!("led_node: {}", err),
}
}
let bright_node = Self::get_kbd_bright_path();
if led_node.is_none() && bright_node.is_none() {
return Err(RogError::MissingFunction(
"All keyboard features missing, you may require a v5.11 series kernel or newer"
.into(),
));
}
if bright_node.is_none() {
return Err(RogError::MissingFunction(
"No brightness control, you may require a v5.11 series kernel or newer".into(),
));
}
let ctrl = CtrlKbdBacklight {
led_node,
bright_node: bright_node.unwrap(), // If was none then we already returned above
supported_modes,
flip_effect_write: false,
config,
};
Ok(ctrl)
}
fn get_kbd_bright_path() -> Option<String> {
if Path::new(KBD_BRIGHT_PATH).exists() {
return Some(KBD_BRIGHT_PATH.to_string());
}
None
}
pub fn get_brightness(&self) -> Result<u8, RogError> {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(buf[0])
}
pub fn set_brightness(&self, brightness: LedBrightness) -> Result<(), RogError> {
let path = Path::new(&self.bright_node);
let mut file =
OpenOptions::new()
.write(true)
.open(&path)
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
file.write_all(&[brightness.as_char_code()])
.map_err(|err| RogError::Read("buffer".into(), err))?;
Ok(())
}
fn find_led_node(id_product: &str) -> Result<String, RogError> {
let mut enumerator = udev::Enumerator::new().map_err(|err| {
warn!("{}", err);
RogError::Udev("enumerator failed".into(), err)
})?;
enumerator.match_subsystem("hidraw").map_err(|err| {
warn!("{}", err);
RogError::Udev("match_subsystem failed".into(), err)
})?;
for device in enumerator.scan_devices().map_err(|err| {
warn!("{}", err);
RogError::Udev("scan_devices failed".into(), err)
})? {
if let Some(parent) = device
.parent_with_subsystem_devtype("usb", "usb_device")
.map_err(|err| {
warn!("{}", err);
RogError::Udev("parent_with_subsystem_devtype failed".into(), err)
})?
{
if parent
.attribute_value("idProduct")
.ok_or_else(|| RogError::NotFound("LED idProduct".into()))?
== id_product
{
if let Some(dev_node) = device.devnode() {
info!("Using device at: {:?} for LED control", dev_node);
return Ok(dev_node.to_string_lossy().to_string());
}
}
}
}
Err(RogError::MissingFunction(
"ASUS LED device node not found".into(),
))
}
pub(crate) fn do_command(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.set_and_save(mode)
}
/// Should only be used if the bytes you are writing are verified correct
#[inline]
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
if let Some(led_node) = &self.led_node {
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
// println!("write: {:02x?}", &message);
return file
.write_all(message)
.map_err(|err| RogError::Write("write_bytes".into(), err));
}
}
Err(RogError::NotSupported)
}
/// Write an effect block
#[inline]
fn write_effect(&mut self, effect: &[Vec<u8>]) -> Result<(), RogError> {
if self.flip_effect_write {
for row in effect.iter().rev() {
self.write_bytes(row)?;
}
} else {
for row in effect.iter() {
self.write_bytes(row)?;
}
}
self.flip_effect_write = !self.flip_effect_write;
Ok(())
}
/// Used to set a builtin mode and save the settings for it
///
/// This needs to be universal so that settings applied by dbus stick
#[inline]
fn set_and_save(&mut self, mode: AuraEffect) -> Result<(), RogError> {
self.config.read();
self.write_mode(&mode)?;
self.config.current_mode = *mode.mode();
self.config.set_builtin(mode);
self.config.write();
Ok(())
}
#[inline]
fn toggle_mode(&mut self, reverse: bool) -> Result<(), RogError> {
let current = self.config.current_mode;
if let Some(idx) = self
.supported_modes
.standard
.iter()
.position(|v| *v == current)
{
let mut idx = idx;
// goes past end of array
if reverse {
if idx == 0 {
idx = self.supported_modes.standard.len() - 1;
} else {
idx -= 1;
}
} else {
idx += 1;
if idx == self.supported_modes.standard.len() {
idx = 0;
}
}
let next = self.supported_modes.standard[idx];
self.config.read();
if let Some(data) = self.config.builtins.get(&next) {
self.write_mode(&data)?;
self.config.current_mode = next;
}
self.config.write();
}
Ok(())
}
#[inline]
fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> {
if !self.supported_modes.standard.contains(&mode.mode()) {
return Err(RogError::NotSupported);
}
let bytes: [u8; LED_MSG_LEN] = mode.into();
self.write_bytes(&bytes)?;
self.write_bytes(&LED_SET)?;
// Changes won't persist unless apply is set
self.write_bytes(&LED_APPLY)?;
Ok(())
}
}

View File

@@ -1,344 +0,0 @@
use crate::{config::Config, error::RogError, GetSupported};
use log::{error, info, warn};
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::BufRead;
use std::io::{Read, Write};
use std::path::Path;
use std::process::Command;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::dbus_interface;
const INITRAMFS_PATH: &str = "/usr/sbin/update-initramfs";
const DRACUT_PATH: &str = "/usr/bin/dracut";
static ASUS_SWITCH_GRAPHIC_MODE: &str =
"/sys/firmware/efi/efivars/AsusSwitchGraphicMode-607005d5-3f75-4b2e-98f0-85ba66797a3e";
static ASUS_POST_LOGO_SOUND: &str =
"/sys/firmware/efi/efivars/AsusPostLogoSound-607005d5-3f75-4b2e-98f0-85ba66797a3e";
pub struct CtrlRogBios {
_config: Arc<Mutex<Config>>,
}
#[derive(Serialize, Deserialize)]
pub struct RogBiosSupportedFunctions {
pub post_sound_toggle: bool,
pub dedicated_gfx_toggle: bool,
}
impl GetSupported for CtrlRogBios {
type A = RogBiosSupportedFunctions;
fn get_supported() -> Self::A {
RogBiosSupportedFunctions {
post_sound_toggle: CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND).is_ok(),
dedicated_gfx_toggle: CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok(),
}
}
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl CtrlRogBios {
pub fn set_dedicated_graphic_mode(&mut self, dedicated: bool) {
self.set_gfx_mode(dedicated)
.map_err(|err| {
warn!("CtrlRogBios: set_asus_switch_graphic_mode {}", err);
err
})
.ok();
self.notify_dedicated_graphic_mode(dedicated)
.map_err(|err| {
warn!("CtrlRogBios: notify_asus_switch_graphic_mode {}", err);
err
})
.ok();
}
pub fn dedicated_graphic_mode(&self) -> i8 {
Self::get_gfx_mode()
.map_err(|err| {
warn!("CtrlRogBios: get_gfx_mode {}", err);
err
})
.unwrap_or(-1)
}
#[dbus_interface(signal)]
pub fn notify_dedicated_graphic_mode(&self, dedicated: bool) -> zbus::Result<()> {}
// // // // // // // // // //
pub fn set_post_boot_sound(&mut self, on: bool) {
Self::set_boot_sound(on)
.map_err(|err| {
warn!("CtrlRogBios: set_post_boot_sound {}", err);
err
})
.ok();
self.notify_post_boot_sound(on)
.map_err(|err| {
warn!("CtrlRogBios: notify_post_boot_sound {}", err);
err
})
.ok();
}
pub fn post_boot_sound(&self) -> i8 {
Self::get_boot_sound()
.map_err(|err| {
warn!("CtrlRogBios: get_boot_sound {}", err);
err
})
.unwrap_or(-1)
}
#[dbus_interface(signal)]
pub fn notify_post_boot_sound(&self, dedicated: bool) -> zbus::Result<()> {}
}
impl crate::ZbusAdd for CtrlRogBios {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/RogBios", self)
.map_err(|err| {
warn!("CtrlRogBios: add_to_server {}", err);
err
})
.ok();
}
}
impl crate::Reloadable for CtrlRogBios {
fn reload(&mut self) -> Result<(), RogError> {
Ok(())
}
}
impl CtrlRogBios {
pub fn new(config: Arc<Mutex<Config>>) -> Result<Self, RogError> {
match CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE) {
Ok(_) => {
CtrlRogBios::set_path_mutable(ASUS_SWITCH_GRAPHIC_MODE)?;
}
Err(err) => {
info!("ROG Switchable Graphics (bios) not detected: {}", err);
}
}
match CtrlRogBios::check_path_exists(ASUS_POST_LOGO_SOUND) {
Ok(_) => {
CtrlRogBios::set_path_mutable(ASUS_POST_LOGO_SOUND)?;
}
Err(err) => {
info!("ROG boot sound toggle (bios) not detected: {}", err);
}
}
Ok(CtrlRogBios { _config: config })
}
fn set_path_mutable(path: &str) -> Result<(), RogError> {
let output = Command::new("/usr/bin/chattr")
.arg("-i")
.arg(path)
.output()
.map_err(|err| RogError::Path(path.into(), err))?;
info!("Set {} writeable: status: {}", path, output.status);
Ok(())
}
fn check_path_exists(path: &str) -> Result<(), RogError> {
if Path::new(path).exists() {
Ok(())
} else {
Err(RogError::MissingFunction(path.into()))
}
}
pub fn has_dedicated_gfx_toggle() -> bool {
if CtrlRogBios::check_path_exists(ASUS_SWITCH_GRAPHIC_MODE).is_ok() {
return true;
}
false
}
pub fn get_gfx_mode() -> Result<i8, RogError> {
let path = ASUS_SWITCH_GRAPHIC_MODE;
let mut file = OpenOptions::new()
.read(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
Ok(data[idx] as i8)
}
pub(super) fn set_gfx_mode(&self, dedicated: bool) -> Result<(), RogError> {
let path = ASUS_SWITCH_GRAPHIC_MODE;
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data).unwrap();
let idx = data.len() - 1;
if dedicated {
data[idx] = 1;
info!("Set system-level graphics mode: Dedicated Nvidia");
} else {
data[idx] = 0;
info!("Set system-level graphics mode: Optimus");
}
file.write_all(&data)
.map_err(|err| RogError::Path(path.into(), err))?;
self.update_initramfs(dedicated)?;
// if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
// if let Ok(vendor) = CtrlGraphics::get_vendor() {
// if ded == 1 && vendor != "nvidia" {
// warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
// CtrlGraphics::set_gfx_config(&GfxVendors::Nvidia)
// .unwrap_or_else(|err| warn!("Gfx controller: {}", err));
// }
// }
// }
Ok(())
}
pub fn get_boot_sound() -> Result<i8, RogError> {
let path = ASUS_POST_LOGO_SOUND;
let mut file = OpenOptions::new()
.read(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
Ok(data[idx] as i8)
}
pub(super) fn set_boot_sound(on: bool) -> Result<(), RogError> {
let path = ASUS_POST_LOGO_SOUND;
let mut file = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.map_err(|err| RogError::Path(path.into(), err))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|err| RogError::Read(path.into(), err))?;
let idx = data.len() - 1;
if on {
data[idx] = 1;
info!("Set boot POST sound on");
} else {
data[idx] = 0;
info!("Set boot POST sound off");
}
file.write_all(&data)
.map_err(|err| RogError::Path(path.into(), err))?;
Ok(())
}
// required for g-sync mode
fn update_initramfs(&self, dedicated: bool) -> Result<(), RogError> {
let mut initfs_cmd = None;
if Path::new(INITRAMFS_PATH).exists() {
let mut cmd = Command::new("update-initramfs");
cmd.arg("-u");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'update-initramfs'");
} else if Path::new(DRACUT_PATH).exists() {
let mut cmd = Command::new("dracut");
cmd.arg("-f");
cmd.arg("-q");
initfs_cmd = Some(cmd);
info!("Using initramfs update command 'dracut'");
}
if let Some(mut cmd) = initfs_cmd {
info!("Updating initramfs");
// If switching to Nvidia dedicated we need these modules included
if Path::new(DRACUT_PATH).exists() && dedicated {
cmd.arg("--add-drivers");
cmd.arg("nvidia nvidia-drm nvidia-modeset nvidia-uvm");
info!("System uses dracut, forcing nvidia modules to be included in init");
} else if Path::new(INITRAMFS_PATH).exists() {
let modules = vec![
"nvidia\n",
"nvidia-drm\n",
"nvidia-modeset\n",
"nvidia-uvm\n",
];
let module_include = Path::new("/etc/initramfs-tools/modules");
if dedicated {
let mut file = std::fs::OpenOptions::new()
.append(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
// add nvidia modules to module_include
file.write_all(modules.concat().as_bytes()).unwrap();
} else {
let file = std::fs::OpenOptions::new()
.read(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
let mut buf = Vec::new();
// remove modules
for line in std::io::BufReader::new(file).lines() {
if let Ok(l) = line {
if !modules.contains(&l.as_ref()) {
buf.append(&mut l.as_bytes().to_vec());
}
}
}
let file = std::fs::OpenOptions::new()
.write(true)
.open(module_include)
.map_err(|err| {
RogError::Write(module_include.to_string_lossy().to_string(), err)
})?;
std::io::BufWriter::new(file).write_all(&buf).unwrap();
}
}
let status = cmd
.status()
.map_err(|err| RogError::Write(format!("{:?}", cmd), err))?;
if !status.success() {
error!("Ram disk update failed");
return Err(RogError::Initramfs("Ram disk update failed".into()));
} else {
info!("Successfully updated initramfs");
}
}
Ok(())
}
}

View File

@@ -1,54 +0,0 @@
use log::warn;
use serde_derive::{Deserialize, Serialize};
use zbus::dbus_interface;
use crate::{
ctrl_anime::{AnimeSupportedFunctions, CtrlAnimeDisplay},
ctrl_charge::{ChargeSupportedFunctions, CtrlCharge},
ctrl_fan_cpu::{CtrlFanAndCPU, FanCpuSupportedFunctions},
ctrl_leds::{CtrlKbdBacklight, LedSupportedFunctions},
ctrl_rog_bios::{CtrlRogBios, RogBiosSupportedFunctions},
GetSupported,
};
#[derive(Serialize, Deserialize)]
pub struct SupportedFunctions {
pub anime_ctrl: AnimeSupportedFunctions,
pub charge_ctrl: ChargeSupportedFunctions,
pub fan_cpu_ctrl: FanCpuSupportedFunctions,
pub keyboard_led: LedSupportedFunctions,
pub rog_bios_ctrl: RogBiosSupportedFunctions,
}
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl SupportedFunctions {
fn supported_functions(&self) -> String {
serde_json::to_string_pretty(self).unwrap()
}
}
impl crate::ZbusAdd for SupportedFunctions {
fn add_to_server(self, server: &mut zbus::ObjectServer) {
server
.at("/org/asuslinux/Supported", self)
.map_err(|err| {
warn!("SupportedFunctions: add_to_server {}", err);
err
})
.ok();
}
}
impl GetSupported for SupportedFunctions {
type A = SupportedFunctions;
fn get_supported() -> Self::A {
SupportedFunctions {
keyboard_led: CtrlKbdBacklight::get_supported(),
anime_ctrl: CtrlAnimeDisplay::get_supported(),
charge_ctrl: CtrlCharge::get_supported(),
fan_cpu_ctrl: CtrlFanAndCPU::get_supported(),
rog_bios_ctrl: CtrlRogBios::get_supported(),
}
}
}

View File

@@ -1,186 +0,0 @@
use daemon::ctrl_leds::{CtrlKbdBacklight, DbusKbdBacklight};
use daemon::{
config::Config, ctrl_supported::SupportedFunctions, laptops::print_board_info, GetSupported,
};
use daemon::{config_aura::AuraConfig, ctrl_charge::CtrlCharge};
use daemon::{ctrl_anime::CtrlAnimeDisplay, ctrl_gfx::gfx::CtrlGraphics};
use daemon::{
ctrl_fan_cpu::{CtrlFanAndCPU, DbusFanAndCpu},
laptops::LaptopLedData,
};
use daemon::{CtrlTask, Reloadable, ZbusAdd};
use log::LevelFilter;
use log::{error, info, warn};
use rog_dbus::DBUS_NAME;
use rog_types::gfx_vendors::GfxVendors;
use std::error::Error;
use std::io::Write;
use std::sync::Arc;
use std::sync::Mutex;
use daemon::ctrl_rog_bios::CtrlRogBios;
use std::convert::Into;
use zbus::fdo;
use zbus::Connection;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
.target(env_logger::Target::Stdout)
.format(|buf, record| writeln!(buf, "{}: {}", record.level(), record.args()))
.filter(None, LevelFilter::Info)
.init();
info!(" daemon v{}", daemon::VERSION);
info!(" rog-dbus v{}", rog_dbus::VERSION);
info!("rog-types v{}", rog_types::VERSION);
start_daemon()?;
Ok(())
}
// Timing is such that:
// - interrupt write is minimum 1ms (sometimes lower)
// - read interrupt must timeout, minimum of 1ms
// - for a single usb packet, 2ms total.
// - to maintain constant times of 1ms, per-key colours should use
// the effect endpoint so that the complete colour block is written
// as fast as 1ms per row of the matrix inside it. (10ms total time)
fn start_daemon() -> Result<(), Box<dyn Error>> {
let supported = SupportedFunctions::get_supported();
print_board_info();
println!("{}", serde_json::to_string_pretty(&supported).unwrap());
let config = Config::load();
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
let connection = Connection::new_system()?;
fdo::DBusProxy::new(&connection)?
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
supported.add_to_server(&mut object_server);
match CtrlRogBios::new(config.clone()) {
Ok(mut ctrl) => {
// Do a reload of any settings
ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("rog_bios_control: {}", err);
}
}
match CtrlCharge::new(config.clone()) {
Ok(mut ctrl) => {
// Do a reload of any settings
ctrl.reload()
.unwrap_or_else(|err| warn!("Battery charge limit: {}", err));
// Then register to dbus server
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("charge_control: {}", err);
}
}
match CtrlAnimeDisplay::new() {
Ok(ctrl) => {
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("AniMe control: {}", err);
}
}
if enable_gfx_switching {
match CtrlGraphics::new(config.clone()) {
Ok(mut ctrl) => {
// Need to check if a laptop has the dedicated gfx switch
if CtrlRogBios::has_dedicated_gfx_toggle() {
if let Ok(ded) = CtrlRogBios::get_gfx_mode() {
if let Ok(vendor) = ctrl.get_gfx_mode() {
if ded == 1 && vendor != GfxVendors::Nvidia {
warn!("Dedicated GFX toggle is on but driver mode is not nvidia \nSetting to nvidia driver mode");
let devices = ctrl.devices();
let bus = ctrl.bus();
CtrlGraphics::do_vendor_tasks(GfxVendors::Nvidia, &devices, &bus)?;
} else if ded == 0 {
info!("Dedicated GFX toggle is off");
}
}
}
}
ctrl.reload()
.unwrap_or_else(|err| error!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
}
// Collect tasks for task thread
let mut tasks: Vec<Arc<Mutex<dyn CtrlTask + Send>>> = Vec::new();
if let Ok(mut ctrl) = CtrlFanAndCPU::new(config).map_err(|err| {
error!("Profile control: {}", err);
}) {
ctrl.reload()
.unwrap_or_else(|err| warn!("Profile control: {}", err));
let tmp = Arc::new(Mutex::new(ctrl));
DbusFanAndCpu::new(tmp).add_to_server(&mut object_server);
};
let laptop = LaptopLedData::get_data();
let aura_config = AuraConfig::load(&laptop);
if let Ok(ctrl) = CtrlKbdBacklight::new(laptop, aura_config).map_err(|err| {
error!("Keyboard control: {}", err);
err
}) {
let tmp = Arc::new(Mutex::new(ctrl));
DbusKbdBacklight::new(tmp.clone()).add_to_server(&mut object_server);
tasks.push(tmp);
}
// TODO: implement messaging between threads to check fails
// These tasks generally read a sys path or file to check for a
// change
let _handle = std::thread::Builder::new()
.name("asusd watch".to_string())
.spawn(move || loop {
std::thread::sleep(std::time::Duration::from_millis(100));
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
}
});
object_server
.with("/org/asuslinux/Charge", |obj: &CtrlCharge| {
let x = obj.limit();
obj.notify_charge(x as u8)
})
.map_err(|err| {
warn!("object_server notify_charge error: {}", err);
})
.ok();
loop {
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);
}
}
}

View File

@@ -1,97 +0,0 @@
use intel_pstate::PStateError;
use rog_fan_curve::CurveError;
use rog_types::error::GraphicsError;
use std::convert::From;
use std::fmt;
use crate::ctrl_gfx::error::GfxError;
#[derive(Debug)]
pub enum RogError {
ParseFanLevel,
ParseVendor,
ParseLED,
MissingProfile(String),
Udev(String, std::io::Error),
Path(String, std::io::Error),
Read(String, std::io::Error),
Write(String, std::io::Error),
NotSupported,
NotFound(String),
IntelPstate(PStateError),
FanCurve(CurveError),
DoTask(String),
MissingFunction(String),
MissingLedBrightNode(String, std::io::Error),
ReloadFail(String),
GfxSwitching(GfxError),
Initramfs(String),
Modprobe(String),
Command(String, std::io::Error),
Io(std::io::Error),
Zbus(zbus::Error),
}
impl fmt::Display for RogError {
// This trait requires `fmt` with this exact signature.
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RogError::ParseFanLevel => write!(f, "Parse profile error"),
RogError::ParseVendor => write!(f, "Parse gfx vendor error"),
RogError::ParseLED => write!(f, "Parse LED error"),
RogError::MissingProfile(profile) => write!(f, "Profile does not exist {}", profile),
RogError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
RogError::Path(path, error) => write!(f, "Path {}: {}", path, error),
RogError::Read(path, error) => write!(f, "Read {}: {}", path, error),
RogError::Write(path, error) => write!(f, "Write {}: {}", path, error),
RogError::NotSupported => write!(f, "Not supported"),
RogError::NotFound(deets) => write!(f, "Not found: {}", deets),
RogError::IntelPstate(err) => write!(f, "Intel pstate error: {}", err),
RogError::FanCurve(err) => write!(f, "Custom fan-curve error: {}", err),
RogError::DoTask(deets) => write!(f, "Task error: {}", deets),
RogError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets),
RogError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error),
RogError::ReloadFail(deets) => write!(f, "Task error: {}", deets),
RogError::GfxSwitching(deets) => write!(f, "Graphics switching error: {}", deets),
RogError::Initramfs(detail) => write!(f, "Initiramfs error: {}", detail),
RogError::Modprobe(detail) => write!(f, "Modprobe error: {}", detail),
RogError::Command(func, error) => write!(f, "Command exec error: {}: {}", func, error),
RogError::Io(detail) => write!(f, "std::io error: {}", detail),
RogError::Zbus(detail) => write!(f, "Zbus error: {}", detail),
}
}
}
impl std::error::Error for RogError {}
impl From<PStateError> for RogError {
fn from(err: PStateError) -> Self {
RogError::IntelPstate(err)
}
}
impl From<CurveError> for RogError {
fn from(err: CurveError) -> Self {
RogError::FanCurve(err)
}
}
impl From<GraphicsError> for RogError {
fn from(err: GraphicsError) -> Self {
match err {
GraphicsError::ParseVendor => RogError::GfxSwitching(GfxError::ParseVendor),
}
}
}
impl From<zbus::Error> for RogError {
fn from(err: zbus::Error) -> Self {
RogError::Zbus(err)
}
}
impl From<std::io::Error> for RogError {
fn from(err: std::io::Error) -> Self {
RogError::Io(err)
}
}

View File

@@ -1,105 +0,0 @@
use log::{info, warn};
use rog_types::aura_modes::AuraModeNum;
use serde_derive::{Deserialize, Serialize};
use std::fs::OpenOptions;
use std::io::Read;
pub const ASUS_LED_MODE_CONF: &str = "/etc/asusd/asusd-ledmodes.toml";
pub const ASUS_KEYBOARD_DEVICES: [&str; 4] = ["1866", "1869", "1854", "19b6"];
pub fn print_board_info() {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_name = dmi.product_name().expect("Could not get product_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
info!("Product name: {}", prod_name.trim());
info!("Product family: {}", prod_family.trim());
info!("Board name: {}", board_name.trim());
}
pub fn print_modes(supported_modes: &[u8]) {
if !supported_modes.is_empty() {
info!("Supported Keyboard LED modes are:");
for mode in supported_modes {
let mode = <&str>::from(&<AuraModeNum>::from(*mode));
info!("- {}", mode);
}
info!(
"If these modes are incorrect you can edit {}",
ASUS_LED_MODE_CONF
);
} else {
info!("No RGB control available");
}
}
#[derive(Debug, Deserialize, Serialize)]
struct LedSupportFile {
led_data: Vec<LaptopLedData>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LaptopLedData {
pub prod_family: String,
pub board_names: Vec<String>,
pub standard: Vec<AuraModeNum>,
pub multizone: bool,
pub per_key: bool,
}
impl LaptopLedData {
pub fn get_data() -> Self {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name().expect("Could not get board_name");
let prod_family = dmi.product_family().expect("Could not get product_family");
if let Some(modes) = LedSupportFile::load_from_config() {
if let Some(data) = modes.matcher(&prod_family, &board_name) {
return data;
}
}
info!("Using generic LED control for keyboard brightness only");
LaptopLedData {
prod_family,
board_names: vec![board_name],
standard: vec![],
multizone: false,
per_key: false,
}
}
}
impl LedSupportFile {
/// Consumes the LEDModes
fn matcher(self, prod_family: &str, board_name: &str) -> Option<LaptopLedData> {
for config in self.led_data {
if prod_family.contains(&config.prod_family) {
for board in &config.board_names {
if board_name.contains(board) {
info!("Matched to {} {}", config.prod_family, board);
return Some(config);
}
}
}
}
None
}
fn load_from_config() -> Option<Self> {
if let Ok(mut file) = OpenOptions::new().read(true).open(&ASUS_LED_MODE_CONF) {
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
warn!("{} is empty", ASUS_LED_MODE_CONF);
} else {
return Some(toml::from_str(&buf).unwrap_or_else(|_| {
panic!("Could not deserialise {}", ASUS_LED_MODE_CONF)
}));
}
}
}
warn!("Does {} exist?", ASUS_LED_MODE_CONF);
None
}
}

View File

@@ -1,64 +0,0 @@
#![deny(unused_must_use)]
/// Configuration loading, saving
pub mod config;
pub mod config_aura;
pub(crate) mod config_old;
/// Control of AniMe matrix display
pub mod ctrl_anime;
/// Control of battery charge level
pub mod ctrl_charge;
/// Control CPU min/max freq and turbo, fan mode, fan curves
///
/// Intel machines can control:
/// - CPU min/max frequency
/// - CPU turbo enable/disable
/// - Fan mode (normal, boost, silent)
///
/// AMD machines can control:
/// - CPU turbo enable/disable
/// - Fan mode (normal, boost, silent)
/// - Fan min/max RPM curve
pub mod ctrl_fan_cpu;
/// GPU switching and power
pub mod ctrl_gfx;
/// Keyboard LED brightness control, RGB, and LED display modes
pub mod ctrl_leds;
/// Control ASUS bios function such as boot sound, Optimus/Dedicated gfx mode
pub mod ctrl_rog_bios;
/// Laptop matching to determine capabilities
pub mod laptops;
/// Fetch all supported functions for the laptop
pub mod ctrl_supported;
mod error;
use crate::error::RogError;
use config::Config;
use zbus::ObjectServer;
pub static VERSION: &str = env!("CARGO_PKG_VERSION");
pub trait Reloadable {
fn reload(&mut self) -> Result<(), RogError>;
}
pub trait ZbusAdd {
fn add_to_server(self, server: &mut ObjectServer);
}
pub trait CtrlTask {
fn do_task(&mut self) -> Result<(), RogError>;
}
pub trait CtrlTaskComplex {
type A;
fn do_task(&mut self, config: &mut Config, event: Self::A);
}
pub trait GetSupported {
type A;
fn get_supported() -> Self::A;
}

View File

@@ -1,7 +0,0 @@
# Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto"
ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto"
# Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on"
ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on"

View File

@@ -1,4 +0,0 @@
Section "ServerLayout"
Identifier "layout"
Option "AllowNVIDIAGPUScreens"
EndSection

View File

@@ -1,50 +0,0 @@
function _asusctl() {
local line
_arguments -C \
{-h,--help}'[print help message]' \
{-v,--version}'[print version number]' \
{-k,--kbd-bright}':[Set keyboard brightness (off, low, med, high)]' \
{-p,--pwr-profile}':[Set power profile (silent, normal, boost)]' \
{-c,--chg-limit}':[Set charging limit (20-100)]' \
': :((led-mode\:"Set the keyboard lighting from built-in modes" profile\:"Create and configure profiles" graphics\:"Set the graphics mode"))' \
'*::arg:->args'
case $line[1] in
led-mode)
_arguments ': :((static\:"set a single static colour"
breathe\:"pulse between one or two colours"
strobe\:"strobe through all colours"
rainbow\:"rainbow cycling in one of four directions"
star\:"rain pattern mimicking raindrops"
rain\:"rain pattern of three preset colours"
highlight\:"pressed keys are highlighted to fade"
laser\:"pressed keys generate horizontal laser"
ripple\:"pressed keys ripple outwards like a splash"
pulse\:"set a rapid pulse"
comet\:"set a vertical line zooming from left"
flash\:"set a wide vertical line zooming from left"
multi-static\:"4-zone multi-colour"))' \
{-h,--help}'[print help message]' \
'-c:[set the RGB value e.g, ff00ff]' \
'-s:[set the speed (low, med, high)]'
;;
profile)
_arguments {-h,--help}'[print help message]' \
{-c,--create}"[create the profile if it doesn't exist]" \
{-t,--turbo}':[enable or disable cpu turbo]' \
{-m,--min-percentage}':[set min cpu scaling (intel)]' \
{-M,--max-percentage}':[set max cpu scaling (intel)]' \
{-p,--preset}':[<silent, normal, boost>]' \
{-C,--curve}':[set fan curve]'
;;
graphics)
_arguments {-h,--help}'[print help message]' \
{-m,--mode}':[Set graphics mode (nvidia, hybrid, compute, integrated)]' \
{-g,--get}'[Get the current mode]' \
{-p,--pow}'[Get the current power status]' \
{-f,--force}'[Do not ask for confirmation]'
;;
esac
}
compdef _asusctl asusctl

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