From 308fba9413f42a05e97cfdbaf9fdce58dafff0fe Mon Sep 17 00:00:00 2001 From: "Luke D. Jones" Date: Fri, 12 Aug 2022 15:22:06 +1200 Subject: [PATCH] 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 --- CHANGELOG.md | 7 + Cargo.lock | 157 ++++++------ Cargo.toml | 2 +- asusctl/src/main.rs | 6 +- daemon/Cargo.toml | 4 +- daemon/src/ctrl_anime/mod.rs | 116 ++------- daemon/src/ctrl_anime/zbus.rs | 21 +- daemon/src/ctrl_aura/config.rs | 12 +- daemon/src/ctrl_aura/controller.rs | 261 ++++++-------------- daemon/src/ctrl_aura/zbus.rs | 2 +- daemon/src/ctrl_rog_bios.rs | 151 ++++------- daemon/src/error.rs | 9 + rog-anime/Cargo.toml | 3 +- rog-anime/src/usb.rs | 24 -- rog-aura/src/layouts/mod.rs | 4 +- rog-control-center/src/app.rs | 37 +-- rog-control-center/src/lib.rs | 8 + rog-control-center/src/main.rs | 135 +++++----- rog-control-center/src/page_states.rs | 6 +- rog-control-center/src/pages/aura_page.rs | 6 +- rog-control-center/src/widgets/fan_graph.rs | 29 +-- rog-control-center/src/widgets/rog_bios.rs | 2 +- rog-dbus/src/zbus_rogbios.rs | 4 +- rog-platform/Cargo.toml | 12 + rog-platform/src/error.rs | 51 ++++ rog-platform/src/hid_raw.rs | 55 +++++ rog-platform/src/keyboard_led.rs | 59 +++++ rog-platform/src/lib.rs | 191 ++++++++++++++ rog-platform/src/platform.rs | 69 ++++++ rog-platform/src/usb_raw.rs | 48 ++++ rog-supported/src/lib.rs | 4 +- 31 files changed, 860 insertions(+), 635 deletions(-) create mode 100644 rog-platform/Cargo.toml create mode 100644 rog-platform/src/error.rs create mode 100644 rog-platform/src/hid_raw.rs create mode 100644 rog-platform/src/keyboard_led.rs create mode 100644 rog-platform/src/lib.rs create mode 100644 rog-platform/src/platform.rs create mode 100644 rog-platform/src/usb_raw.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 161d14f1..9c821fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased ] +### Changed +- Create new rog-platform crate to manage all i/o in a universal way + + kbd-led handling (requires kernel patches, TUF specific) + + platform handling (asus-nb-wmi) + + hidraw + + usbraw +- Refactor how ROGCC handles IPC for background open, run-in-bg ## [4.3.4] - 2022-08-03 ### Bugfix diff --git a/Cargo.lock b/Cargo.lock index c13db865..d5896c5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -119,9 +119,9 @@ dependencies = [ [[package]] name = "async-channel" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28" dependencies = [ "concurrent-queue", "event-listener", @@ -228,9 +228,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" [[package]] name = "async-trait" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" dependencies = [ "proc-macro2", "quote", @@ -332,9 +332,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" [[package]] name = "cache-padded" @@ -435,9 +435,9 @@ checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] name = "combine" -version = "4.6.4" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a604e93b79d1808327a6fca85a6f2d69de66461e7620f5a4cbf5fb4d1d7c948" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" dependencies = [ "bytes", "memchr", @@ -445,9 +445,9 @@ dependencies = [ [[package]] name = "concurrent-queue" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" +checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c" dependencies = [ "cache-padded", ] @@ -551,16 +551,15 @@ dependencies = [ "rog_anime", "rog_aura", "rog_dbus", + "rog_platform", "rog_profiles", "rog_supported", - "rusb", "serde", "serde_derive", "serde_json", "smol", "sysfs-class", "toml", - "udev", "zbus", "zvariant", ] @@ -740,7 +739,7 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650" [[package]] name = "eframe" version = "0.18.0" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "bytemuck", "dark-light", @@ -761,7 +760,7 @@ dependencies = [ [[package]] name = "egui" version = "0.18.1" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "ahash 0.7.6", "epaint", @@ -772,7 +771,7 @@ dependencies = [ [[package]] name = "egui-winit" version = "0.18.0" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "arboard", "egui", @@ -786,7 +785,7 @@ dependencies = [ [[package]] name = "egui_glow" version = "0.18.1" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "bytemuck", "egui", @@ -800,7 +799,7 @@ dependencies = [ [[package]] name = "emath" version = "0.18.0" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "bytemuck", ] @@ -865,7 +864,7 @@ dependencies = [ [[package]] name = "epaint" version = "0.18.1" -source = "git+https://github.com/emilk/egui#a7012cf8a628d125b211fd164ac12fbb898f316e" +source = "git+https://github.com/emilk/egui#7c25a9238e8b899b4d5653db98a583e69b790b17" dependencies = [ "ab_glyph", "ahash 0.7.6", @@ -888,9 +887,9 @@ dependencies = [ [[package]] name = "event-listener" -version = "2.5.2" +version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" @@ -1038,9 +1037,9 @@ dependencies = [ [[package]] name = "glam" -version = "0.21.2" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781aa11be58ef14b0cd7326618afcbd9cdb5ba686bdab7193d87cdc322cd7033" +checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" dependencies = [ "serde", ] @@ -1086,9 +1085,9 @@ dependencies = [ [[package]] name = "glutin_egl_sys" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +checksum = "68900f84b471f31ea1d1355567eb865a2cf446294f06cef8d653ed7bcf5f013d" dependencies = [ "gl_generator", "winapi", @@ -1112,9 +1111,9 @@ dependencies = [ [[package]] name = "glutin_glx_sys" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +checksum = "d93d0575865098580c5b3a423188cd959419912ea60b1e48e8b3b526f6d02468" dependencies = [ "gl_generator", "x11-dl", @@ -1219,9 +1218,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754" [[package]] name = "jni" @@ -1266,9 +1265,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "04c3b4822ccebfa39c02fc03d1534441b22ead323fa0f48bb7ddd8e6ba076a40" [[package]] name = "libloading" @@ -1292,9 +1291,9 @@ dependencies = [ [[package]] name = "libusb1-sys" -version = "0.6.2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dfab089105aa85a3b492b421bd90d55e6257f00f8447cc3873c44f8206809ce" +checksum = "f9d0e2afce4245f2c9a418511e5af8718bcaf2fa408aefb259504d1a9cb25f27" dependencies = [ "cc", "libc", @@ -1334,9 +1333,9 @@ dependencies = [ [[package]] name = "mac-notification-sys" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff231a88fe2e9985f9d159a2f02986fe46daa0f6af976a0d934be4870cc9d02" +checksum = "3e72d50edb17756489e79d52eb146927bec8eba9dd48faadf9ef08bca3791ad5" dependencies = [ "cc", "dirs-next", @@ -1377,9 +1376,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a79b39c93a7a5a27eeaf9a23b5ff43f1b9e0ad6b1cdd441140ae53c35613fc7" +checksum = "8e2e4455be2010e8c5e77f0d10234b30f3a636a5305725609b5a71ad00d22577" dependencies = [ "libc", ] @@ -1718,9 +1717,9 @@ dependencies = [ [[package]] name = "owned_ttf_parser" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1e509cfe7a12db2a90bfa057dfcdbc55a347f5da677c506b53dd099cfec9d" +checksum = "07ef1a404ae479dd6906f4fa2c88b3c94028f1284beb42a47c183a7c27ee9a3e" dependencies = [ "ttf-parser", ] @@ -1840,28 +1839,29 @@ checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" dependencies = [ + "once_cell", "thiserror", "toml", ] [[package]] name = "proc-macro2" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +checksum = "0a2ca2c61bc9f3d74d2886294ab7b9853abd9c1ad903a3ac7815c58989bb7bab" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] @@ -1907,9 +1907,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -1985,7 +1985,6 @@ dependencies = [ "serde", "serde_derive", "sysfs-class", - "udev", "zbus", "zvariant", ] @@ -2013,6 +2012,16 @@ dependencies = [ "zvariant", ] +[[package]] +name = "rog_platform" +version = "0.1.0" +dependencies = [ + "log", + "rusb", + "sysfs-class", + "udev", +] + [[package]] name = "rog_profiles" version = "1.1.3" @@ -2057,9 +2066,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" [[package]] name = "same-file" @@ -2084,18 +2093,18 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "serde" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "53e8e5d5b70924f74ff5c6d64d9a5acd91422117c60f48c4e07855238a254553" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.143" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "d3d8e8de557aee63c26b85b947f5e59b690d0454c753f3adeb5cd7835ab88391" dependencies = [ "proc-macro2", "quote", @@ -2104,9 +2113,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7" dependencies = [ "itoa", "ryu", @@ -2115,9 +2124,9 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ad84e47328a31223de7fed7a4f5087f2d6ddfe586cf3ca25b7a165bc0a5aed" +checksum = "1fe39d9fbb0ebf5eb2c7cb7e2a47e4f462fad1379f1166b8ae49ad9eae89a7ca" dependencies = [ "proc-macro2", "quote", @@ -2221,7 +2230,7 @@ dependencies = [ "dlib", "lazy_static", "log", - "memmap2 0.5.5", + "memmap2 0.5.6", "nix 0.24.2", "pkg-config", "wayland-client", @@ -2308,9 +2317,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "58dbef6ec655055e20b86b15a8cc6d439cca19b667537ac6a1369572d151ab13" dependencies = [ "proc-macro2", "quote", @@ -2351,18 +2360,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "f5f6586b7f764adc0231f4c79be7b920e766bb2f3e51b3661cdb263828f19994" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "12bafc5b54507e0149cdf1b145a5d80ab80a90bcd9275df43d4fff68460f6c21" dependencies = [ "proc-macro2", "quote", @@ -2371,9 +2380,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c91f41dcb2f096c05f0873d667dceec1087ce5bcf984ec8ffb19acddbb3217" +checksum = "db76ff9fa4b1458b3c7f077f3ff9887394058460d21e634355b273aaf11eea45" dependencies = [ "libc", "num_threads", @@ -2415,9 +2424,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +checksum = "2fce9567bd60a67d08a16488756721ba392f24f29006402881e43b19aac64307" dependencies = [ "cfg-if 1.0.0", "pin-project-lite", @@ -2438,9 +2447,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7" dependencies = [ "once_cell", ] @@ -2480,9 +2489,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "c4f5b37a154999a8f3f98cc23a628d850e154479cd94decf3414696e12e31aaf" [[package]] name = "unicode-normalization" @@ -2914,9 +2923,9 @@ dependencies = [ [[package]] name = "x11-dl" -version = "2.19.1" +version = "2.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" +checksum = "0c83627bc137605acc00bb399c7b908ef460b621fc37c953db2b09f88c449ea6" dependencies = [ "lazy_static", "libc", diff --git a/Cargo.toml b/Cargo.toml index b2caec6f..6999b882 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-supported", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"] +members = ["asusctl", "asus-notify", "daemon", "daemon-user", "rog-platform", "rog-supported", "rog-dbus", "rog-anime", "rog-aura", "rog-profiles", "rog-control-center"] [profile.release] # thin = 57s, asusd = 9.0M diff --git a/asusctl/src/main.rs b/asusctl/src/main.rs index 5476ff4e..f79a6ca8 100644 --- a/asusctl/src/main.rs +++ b/asusctl/src/main.rs @@ -774,7 +774,7 @@ fn handle_bios_option( for line in usage.iter().filter(|line| { line.contains("sound") && supported.post_sound - || line.contains("GPU") && supported.dedicated_gfx + || line.contains("GPU") && supported.dgpu_only || line.contains("panel") && supported.panel_overdrive }) { println!("{}", line); @@ -802,7 +802,7 @@ fn handle_bios_option( } } if cmd.dedicated_gfx_get { - let res = dbus.proxies().rog_bios().dedicated_graphic_mode()? == 1; + let res = dbus.proxies().rog_bios().dedicated_graphic_mode()?; println!("Bios dedicated GPU on: {}", res); } @@ -810,7 +810,7 @@ fn handle_bios_option( dbus.proxies().rog_bios().set_panel_overdrive(opt)?; } if cmd.panel_overdrive_get { - let res = dbus.proxies().rog_bios().panel_overdrive()? == 1; + let res = dbus.proxies().rog_bios().panel_overdrive()?; println!("Panel overdrive on: {}", res); } } diff --git a/daemon/Cargo.toml b/daemon/Cargo.toml index 99d882a3..91f0410e 100644 --- a/daemon/Cargo.toml +++ b/daemon/Cargo.toml @@ -21,15 +21,13 @@ path = "src/daemon.rs" rog_anime = { path = "../rog-anime", features = ["dbus"] } rog_aura = { path = "../rog-aura", features = ["dbus"] } rog_supported = { path = "../rog-supported" } +rog_platform = { path = "../rog-platform" } rog_profiles = { path = "../rog-profiles" } rog_dbus = { path = "../rog-dbus" } async-trait = "^0.1" smol = "^1.2" -rusb = "^0.9" -udev = "^0.6" - # cli and logging log = "^0.4" env_logger = "^0.9" diff --git a/daemon/src/ctrl_anime/mod.rs b/daemon/src/ctrl_anime/mod.rs index 6a3f8a4d..67978419 100644 --- a/daemon/src/ctrl_anime/mod.rs +++ b/daemon/src/ctrl_anime/mod.rs @@ -8,25 +8,21 @@ use logind_zbus::manager::ManagerProxy; use rog_anime::{ error::AnimeError, usb::{ - find_node, get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, - pkts_for_init, PROD_ID, VENDOR_ID, + get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, + pkts_for_init, }, ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, }; +use rog_platform::{hid_raw::HidRaw, usb_raw::USBRaw}; use rog_supported::AnimeSupportedFunctions; -use rusb::{Device, DeviceHandle}; use smol::{stream::StreamExt, Executor}; +use std::sync::atomic::{AtomicBool, Ordering}; use std::{ - cell::RefCell, convert::TryFrom, error::Error, sync::{Arc, Mutex, MutexGuard}, thread::sleep, }; -use std::{ - sync::atomic::{AtomicBool, Ordering}, - time::Duration, -}; use crate::{error::RogError, GetSupported}; @@ -36,14 +32,13 @@ impl GetSupported for CtrlAnime { type A = AnimeSupportedFunctions; fn get_supported() -> Self::A { - AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok()) + AnimeSupportedFunctions(HidRaw::new("193b").is_ok()) } } pub struct CtrlAnime { - _node: String, + node: USBRaw, anime_type: AnimeType, - handle: RefCell>, cache: AnimeConfigCached, config: AnimeConfig, // set to force thread to exit @@ -55,57 +50,26 @@ pub struct CtrlAnime { impl CtrlAnime { #[inline] pub fn new(config: AnimeConfig) -> Result> { - let node = find_node("193b")?; + let node = USBRaw::new(0x193b)?; let anime_type = get_anime_type()?; - let device = Self::get_dev_handle()?; info!("Device has an AniMe Matrix display"); let mut cache = AnimeConfigCached::default(); cache.init_from_config(&config, anime_type)?; let ctrl = CtrlAnime { - _node: node, + node, anime_type, - handle: RefCell::new(device), cache, config, thread_exit: Arc::new(AtomicBool::new(false)), thread_running: Arc::new(AtomicBool::new(false)), }; - ctrl.do_initialization(); + ctrl.do_initialization()?; Ok(ctrl) } - - fn get_dev_handle() -> Result, Box> { - // We don't expect this ID to ever change - let device = CtrlAnime::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 - })?; - - Ok(device) - } - - fn get_device(vendor: u16, product: u16) -> Result, 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) - } + // 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. @@ -230,45 +194,6 @@ impl CtrlAnime { .ok(); } - fn write_bytes(&self, message: &[u8]) { - // if let Ok(mut file) = OpenOptions::new().write(true).open(&self.node) { - // println!("write: {:02x?}", &message); - // return file - // .write_all(message).unwrap(); - // } - let mut error = false; - - match self.handle.borrow().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 = true; - error!("Failed to write to led interrupt: {}", err); - } - }, - } - - if error { - warn!("Will attempt to get AniMe device handle again"); - match Self::get_dev_handle() { - Ok(dev) => { - self.handle.replace(dev); - } - Err(err) => { - error!("Failed to get AniMe device: {}", err); - } - } - } - } - /// 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> { @@ -281,16 +206,17 @@ impl CtrlAnime { } let data = AnimePacketType::try_from(buffer)?; for row in data.iter() { - self.write_bytes(row); + self.node.write_bytes(row)?; } - self.write_bytes(&pkt_for_flush()); + self.node.write_bytes(&pkt_for_flush())?; Ok(()) } - fn do_initialization(&self) { + fn do_initialization(&self) -> Result<(), RogError> { let pkts = pkts_for_init(); - self.write_bytes(&pkts[0]); - self.write_bytes(&pkts[1]); + self.node.write_bytes(&pkts[0])?; + self.node.write_bytes(&pkts[1])?; + Ok(()) } } @@ -380,10 +306,12 @@ pub struct CtrlAnimeReloader(pub Arc>); impl crate::Reloadable for CtrlAnimeReloader { fn reload(&mut self) -> Result<(), RogError> { if let Ok(lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_on(lock.config.awake_enabled)); - lock.write_bytes(&pkt_for_apply()); - lock.write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled)); - lock.write_bytes(&pkt_for_apply()); + lock.node + .write_bytes(&pkt_for_set_on(lock.config.awake_enabled))?; + lock.node.write_bytes(&pkt_for_apply())?; + lock.node + .write_bytes(&pkt_for_set_boot(lock.config.boot_anim_enabled))?; + lock.node.write_bytes(&pkt_for_apply())?; let action = lock.cache.boot.clone(); CtrlAnime::run_thread(self.0.clone(), action, true); diff --git a/daemon/src/ctrl_anime/zbus.rs b/daemon/src/ctrl_anime/zbus.rs index f0a92b15..a71c3600 100644 --- a/daemon/src/ctrl_anime/zbus.rs +++ b/daemon/src/ctrl_anime/zbus.rs @@ -64,7 +64,12 @@ impl CtrlAnimeZbus { let states; 'outer: loop { if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_on(status)); + lock.node + .write_bytes(&pkt_for_set_on(status)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); lock.config.awake_enabled = status; lock.config.write(); @@ -86,8 +91,18 @@ impl CtrlAnimeZbus { let states; 'outer: loop { if let Ok(mut lock) = self.0.try_lock() { - lock.write_bytes(&pkt_for_set_boot(on)); - lock.write_bytes(&pkt_for_apply()); + lock.node + .write_bytes(&pkt_for_set_boot(on)) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); + lock.node + .write_bytes(&pkt_for_apply()) + .map_err(|err| { + warn!("rog_anime::run_animation:callback {}", err); + }) + .ok(); lock.config.boot_anim_enabled = on; lock.config.write(); diff --git a/daemon/src/ctrl_aura/config.rs b/daemon/src/ctrl_aura/config.rs index 58f4bfc4..1489d60c 100644 --- a/daemon/src/ctrl_aura/config.rs +++ b/daemon/src/ctrl_aura/config.rs @@ -2,13 +2,13 @@ use crate::laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}; use log::{error, warn}; use rog_aura::usb::{AuraDev1866, AuraDev19b6, AuraDevTuf, AuraDevice, AuraPowerDev}; use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Direction, LedBrightness, Speed, GRADIENT}; +use rog_platform::hid_raw::HidRaw; +use rog_platform::keyboard_led::KeyboardLed; use serde_derive::{Deserialize, Serialize}; use std::collections::{BTreeMap, HashSet}; use std::fs::{File, OpenOptions}; use std::io::{Read, Write}; -use super::controller::CtrlKbdLed; - pub static AURA_CONFIG_PATH: &str = "/etc/asusd/aura.conf"; /// Enable/disable LED control in various states such as @@ -128,14 +128,16 @@ impl Default for AuraConfig { fn default() -> Self { let mut prod_id = AuraDevice::Unknown; for prod in ASUS_KEYBOARD_DEVICES.iter() { - if let Ok(_) = CtrlKbdLed::find_led_node(prod) { + if let Ok(_) = HidRaw::new(prod) { prod_id = AuraDevice::from(*prod); break; } } - if CtrlKbdLed::get_tuf_mode_path().is_some() { - prod_id = AuraDevice::Tuf; + if let Ok(p) = KeyboardLed::new() { + if p.has_keyboard_rgb_mode() { + prod_id = AuraDevice::Tuf; + } } let enabled = if prod_id == AuraDevice::X19B6 { diff --git a/daemon/src/ctrl_aura/controller.rs b/daemon/src/ctrl_aura/controller.rs index b6df2909..569542ea 100644 --- a/daemon/src/ctrl_aura/controller.rs +++ b/daemon/src/ctrl_aura/controller.rs @@ -1,8 +1,3 @@ -// Only these two packets must be 17 bytes -static KBD_BRIGHT_PATH: &str = "/sys/class/leds/asus::kbd_backlight/brightness"; -static TUF_RGB_MODE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/tuf_krgb_mode"; -static TUF_RGB_STATE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/tuf_krgb_state"; - use crate::{ error::RogError, laptops::{LaptopLedData, ASUS_KEYBOARD_DEVICES}, @@ -16,16 +11,13 @@ use rog_aura::{ AuraEffect, LedBrightness, LED_MSG_LEN, }; use rog_aura::{AuraZone, Direction, Speed, GRADIENT}; +use rog_platform::{hid_raw::HidRaw, keyboard_led::KeyboardLed}; use rog_supported::LedSupportedFunctions; use smol::{stream::StreamExt, Executor}; -use std::path::Path; +use std::collections::BTreeMap; use std::sync::Arc; use std::sync::Mutex; -use std::{ - collections::BTreeMap, - io::{Read, Write}, -}; -use std::{fs::OpenOptions, sync::MutexGuard}; +use std::sync::MutexGuard; use zbus::Connection; use crate::GetSupported; @@ -44,19 +36,21 @@ impl GetSupported for CtrlKbdLed { let mut prod_id = AuraDevice::Unknown; for prod in ASUS_KEYBOARD_DEVICES.iter() { - if let Ok(_) = Self::find_led_node(prod) { + if let Ok(_) = HidRaw::new(prod) { prod_id = AuraDevice::from(*prod); break; } } - if Self::get_tuf_mode_path().is_some() { - prod_id = AuraDevice::Tuf; + if let Ok(p) = KeyboardLed::new() { + if p.has_keyboard_rgb_mode() { + prod_id = AuraDevice::Tuf; + } } LedSupportedFunctions { prod_id, - brightness_set: CtrlKbdLed::get_kbd_bright_path().is_some(), + brightness_set: KeyboardLed::new().is_ok(), stock_led_modes, multizone_led_mode, per_key_led_mode, @@ -66,8 +60,8 @@ impl GetSupported for CtrlKbdLed { #[derive(Debug, PartialEq, PartialOrd)] pub enum LEDNode { - Tuf, - Rog(String), + KbdLed(KeyboardLed), + Rog(HidRaw), None, } @@ -75,7 +69,7 @@ pub struct CtrlKbdLed { // TODO: config stores the keyboard type as an AuraPower, use or update this pub led_prod: Option, pub led_node: LEDNode, - pub bright_node: String, + pub kd_brightness: KeyboardLed, pub supported_modes: LaptopLedData, pub flip_effect_write: bool, pub config: AuraConfig, @@ -91,27 +85,11 @@ impl CtrlKbdLedTask { } fn update_config(lock: &mut CtrlKbdLed) -> Result<(), RogError> { - let mut file = OpenOptions::new() - .read(true) - .open(&lock.bright_node) - .map_err(|err| match err.kind() { - std::io::ErrorKind::NotFound => { - RogError::MissingLedBrightNode((&lock.bright_node).into(), err) - } - _ => RogError::Path((&lock.bright_node).into(), err), - })?; - let mut buf = [0u8; 1]; - file.read_exact(&mut buf) - .map_err(|err| RogError::Read("buffer".into(), err))?; - if let Some(num) = char::from(buf[0]).to_digit(10) { - if lock.config.brightness != num.into() { - lock.config.read(); - lock.config.brightness = num.into(); - lock.config.write(); - } - return Ok(()); - } - Err(RogError::ParseLed) + let bright = lock.kd_brightness.get_brightness()?; + lock.config.read(); + lock.config.brightness = (bright as u32).into(); + lock.config.write(); + return Ok(()); } } @@ -189,9 +167,7 @@ impl crate::Reloadable for CtrlKbdLedReloader { fn reload(&mut self) -> Result<(), RogError> { if let Ok(mut ctrl) = self.0.try_lock() { ctrl.write_current_config_mode()?; - ctrl.set_power_states(&ctrl.config) - .map_err(|err| warn!("{err}")) - .ok(); + ctrl.set_power_states().map_err(|err| warn!("{err}")).ok(); } Ok(()) } @@ -210,7 +186,7 @@ impl CtrlKbdLed { let mut led_prod = None; let mut led_node = None; for prod in ASUS_KEYBOARD_DEVICES.iter() { - match Self::find_led_node(prod) { + match HidRaw::new(prod) { Ok(node) => { led_prod = Some(prod.to_string()); led_node = Some(node); @@ -221,10 +197,10 @@ impl CtrlKbdLed { } } - let bright_node = Self::get_kbd_bright_path(); - let tuf_node = Self::get_tuf_mode_path().is_some() || Self::get_tuf_state_path().is_some(); + let bright_node = KeyboardLed::new(); + let platform = KeyboardLed::new()?; - if led_node.is_none() && tuf_node && bright_node.is_none() { + if led_node.is_none() && !platform.has_keyboard_rgb_mode() { let dmi = sysfs_class::DmiId::default(); if let Ok(prod_family) = dmi.product_family() { if prod_family.contains("TUF") { @@ -237,9 +213,9 @@ impl CtrlKbdLed { let led_node = if let Some(rog) = led_node { info!("Found ROG USB keyboard"); LEDNode::Rog(rog) - } else if tuf_node { + } else if platform.has_keyboard_rgb_mode() { info!("Found TUF keyboard"); - LEDNode::Tuf + LEDNode::KbdLed(platform) } else { LEDNode::None }; @@ -247,7 +223,7 @@ impl CtrlKbdLed { let ctrl = CtrlKbdLed { led_prod, led_node, - bright_node: bright_node.unwrap(), // If was none then we already returned above + kd_brightness: bright_node?, // If was none then we already returned above supported_modes, flip_effect_write: false, config, @@ -255,58 +231,16 @@ impl CtrlKbdLed { Ok(ctrl) } - fn get_kbd_bright_path() -> Option { - if Path::new(KBD_BRIGHT_PATH).exists() { - return Some(KBD_BRIGHT_PATH.to_string()); - } - None - } - - pub fn get_tuf_mode_path() -> Option { - if Path::new(TUF_RGB_MODE_PATH).exists() { - return Some(TUF_RGB_MODE_PATH.to_string()); - } - None - } - - fn get_tuf_state_path() -> Option { - if Path::new(TUF_RGB_STATE_PATH).exists() { - return Some(TUF_RGB_STATE_PATH.to_string()); - } - None - } - pub(super) fn get_brightness(&self) -> Result { - 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]) + self.kd_brightness + .get_brightness() + .map_err(|e| RogError::Platform(e)) } pub(super) 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(()) + self.kd_brightness + .set_brightness(brightness.as_char_code()) + .map_err(|e| RogError::Platform(e)) } pub fn next_brightness(&mut self) -> Result<(), RogError> { @@ -332,68 +266,24 @@ impl CtrlKbdLed { } /// Set combination state for boot animation/sleep animation/all leds/keys leds/side leds LED active - pub(super) fn set_power_states(&self, config: &AuraConfig) -> Result<(), RogError> { - if LEDNode::Tuf == self.led_node { - if let Some(path) = Self::get_tuf_state_path() { - let mut file = OpenOptions::new().write(true).open(path)?; - if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&config.enabled) { - let buf = format!( - "1 {} {} {} {}", - pwr[1] as u8, pwr[2] as u8, pwr[3] as u8, pwr[4] as u8, - ); - file.write_all(buf.as_bytes())?; - } + pub(super) fn set_power_states(&mut self) -> Result<(), RogError> { + if let LEDNode::KbdLed(platform) = &mut self.led_node { + if let Some(pwr) = AuraPowerConfig::to_tuf_bool_array(&self.config.enabled) { + let buf = [1, pwr[1] as u8, pwr[2] as u8, pwr[3] as u8, pwr[4] as u8]; + platform.set_keyboard_rgb_state(&buf)?; } - } else { - let bytes = AuraPowerConfig::to_bytes(&config.enabled); + } else if let LEDNode::Rog(hid_raw) = &self.led_node { + let bytes = AuraPowerConfig::to_bytes(&self.config.enabled); let message = [0x5d, 0xbd, 0x01, bytes[0], bytes[1], bytes[2]]; - self.write_bytes(&message)?; - self.write_bytes(&LED_SET)?; + hid_raw.write_bytes(&message)?; + hid_raw.write_bytes(&LED_SET)?; // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; + hid_raw.write_bytes(&LED_APPLY)?; } Ok(()) } - pub(crate) fn find_led_node(id_product: &str) -> Result { - 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(), - )) - } - /// 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 @@ -414,28 +304,17 @@ impl CtrlKbdLed { Ok(()) } - /// Should only be used if the bytes you are writing are verified correct - fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> { - if let LEDNode::Rog(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::NoAuraNode) - } - /// Write an effect block. This is for per-key fn _write_effect(&mut self, effect: &[Vec]) -> 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)?; + if let LEDNode::Rog(hid_raw) = &self.led_node { + if self.flip_effect_write { + for row in effect.iter().rev() { + hid_raw.write_bytes(row)?; + } + } else { + for row in effect.iter() { + hid_raw.write_bytes(row)?; + } } } self.flip_effect_write = !self.flip_effect_write; @@ -478,19 +357,24 @@ impl CtrlKbdLed { } fn write_mode(&self, mode: &AuraEffect) -> Result<(), RogError> { - if LEDNode::Tuf == self.led_node { - let mut file = OpenOptions::new().write(true).open(TUF_RGB_MODE_PATH)?; - let buf = format!( - "1 {} {} {} {} {}", - mode.mode as u8, mode.colour1.0, mode.colour1.1, mode.colour1.2, mode.speed as u8, - ); - file.write_all(buf.as_bytes())?; - } else { + if let LEDNode::KbdLed(platform) = &self.led_node { + let buf = [ + 1, + mode.mode as u8, + mode.colour1.0, + mode.colour1.1, + mode.colour1.2, + mode.speed as u8, + ]; + platform.set_keyboard_rgb_mode(&buf)?; + } else if let LEDNode::Rog(hid_raw) = &self.led_node { let bytes: [u8; LED_MSG_LEN] = mode.into(); - self.write_bytes(&bytes)?; - self.write_bytes(&LED_SET)?; + hid_raw.write_bytes(&bytes)?; + hid_raw.write_bytes(&LED_SET)?; // Changes won't persist unless apply is set - self.write_bytes(&LED_APPLY)?; + hid_raw.write_bytes(&LED_APPLY)?; + } else { + return Err(RogError::NoAuraKeyboard); } Ok(()) } @@ -562,6 +446,7 @@ impl CtrlKbdLed { #[cfg(test)] mod tests { use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour}; + use rog_platform::keyboard_led::KeyboardLed; use crate::{ ctrl_aura::{config::AuraConfig, controller::LEDNode}, @@ -585,7 +470,7 @@ mod tests { let mut controller = CtrlKbdLed { led_prod: None, led_node: LEDNode::None, - bright_node: String::new(), + kd_brightness: KeyboardLed::default(), supported_modes, flip_effect_write: false, config, @@ -601,7 +486,7 @@ mod tests { .set_effect(effect.clone()) .unwrap_err() .to_string(), - "No Aura keyboard node found" + "No supported Aura keyboard" ); effect.mode = AuraModeNum::Laser; @@ -629,7 +514,7 @@ mod tests { .set_effect(effect.clone()) .unwrap_err() .to_string(), - "No Aura keyboard node found" + "No supported Aura keyboard" ); } @@ -647,7 +532,7 @@ mod tests { let mut controller = CtrlKbdLed { led_prod: None, led_node: LEDNode::None, - bright_node: String::new(), + kd_brightness: KeyboardLed::default(), supported_modes, flip_effect_write: false, config, @@ -684,7 +569,7 @@ mod tests { let mut controller = CtrlKbdLed { led_prod: None, led_node: LEDNode::None, - bright_node: String::new(), + kd_brightness: KeyboardLed::default(), supported_modes, flip_effect_write: false, config, @@ -699,7 +584,7 @@ mod tests { .write_current_config_mode() .unwrap_err() .to_string(), - "No Aura keyboard node found" + "No supported Aura keyboard" ); assert!(controller.config.multizone.is_some()); diff --git a/daemon/src/ctrl_aura/zbus.rs b/daemon/src/ctrl_aura/zbus.rs index c679c40c..38313c80 100644 --- a/daemon/src/ctrl_aura/zbus.rs +++ b/daemon/src/ctrl_aura/zbus.rs @@ -78,7 +78,7 @@ impl CtrlKbdLedZbus { ctrl.config.write(); - ctrl.set_power_states(&ctrl.config).map_err(|e| { + ctrl.set_power_states().map_err(|e| { warn!("{}", e); e })?; diff --git a/daemon/src/ctrl_rog_bios.rs b/daemon/src/ctrl_rog_bios.rs index dabf565e..104ece3f 100644 --- a/daemon/src/ctrl_rog_bios.rs +++ b/daemon/src/ctrl_rog_bios.rs @@ -1,6 +1,7 @@ use crate::{config::Config, error::RogError, GetSupported}; use async_trait::async_trait; use log::{error, info, warn}; +use rog_platform::platform::AsusPlatform; use rog_supported::RogBiosSupportedFunctions; use std::fs::OpenOptions; use std::io::BufRead; @@ -15,15 +16,13 @@ use zbus::{dbus_interface, SignalContext}; 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_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"; -static ASUS_PANEL_OD_PATH: &str = "/sys/devices/platform/asus-nb-wmi/panel_od"; -static ASUS_DGPU_DISABLE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/dgpu_disable"; -static ASUS_EGPU_ENABLE_PATH: &str = "/sys/devices/platform/asus-nb-wmi/egpu_enable"; pub struct CtrlRogBios { + platform: AsusPlatform, _config: Arc>, } @@ -31,12 +30,24 @@ impl GetSupported for CtrlRogBios { type A = RogBiosSupportedFunctions; fn get_supported() -> Self::A { + let mut panel_overdrive = false; + let mut dgpu_disable = false; + let mut egpu_enable = false; + let mut dgpu_only = false; + + if let Ok(platform) = AsusPlatform::new() { + panel_overdrive = platform.has_panel_od(); + dgpu_disable = platform.has_dgpu_disable(); + egpu_enable = platform.has_egpu_enable(); + dgpu_only = platform.has_gpu_mux_mode(); + } + RogBiosSupportedFunctions { post_sound: Path::new(ASUS_POST_LOGO_SOUND).exists(), - dedicated_gfx: Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists(), - panel_overdrive: Path::new(ASUS_PANEL_OD_PATH).exists(), - dgpu_disable: Path::new(ASUS_DGPU_DISABLE_PATH).exists(), - egpu_enable: Path::new(ASUS_EGPU_ENABLE_PATH).exists(), + dgpu_only, + panel_overdrive, + dgpu_disable, + egpu_enable, } } } @@ -59,13 +70,14 @@ impl CtrlRogBios { .ok(); } - fn dedicated_graphic_mode(&self) -> i8 { - Self::get_gfx_mode() + fn dedicated_graphic_mode(&self) -> bool { + self.platform + .get_gpu_mux_mode() .map_err(|err| { warn!("CtrlRogBios: get_gfx_mode {}", err); err }) - .unwrap_or(-1) + .unwrap_or(false) } #[dbus_interface(signal)] @@ -118,26 +130,14 @@ impl CtrlRogBios { } } - fn panel_overdrive(&self) -> i8 { - let path = ASUS_PANEL_OD_PATH; - if let Ok(mut file) = OpenOptions::new().read(true).open(path).map_err(|err| { - warn!("CtrlRogBios: panel_overdrive {}", err); - err - }) { - let mut buf = Vec::new(); - file.read_to_end(&mut buf) - .map_err(|err| { - warn!("CtrlRogBios: set_panel_overdrive {}", err); - err - }) - .ok(); - - if buf.len() >= 1 { - let tmp = String::from_utf8_lossy(&buf[0..1]); - return tmp.parse::().unwrap_or(-1); - } - } - -1 + fn panel_overdrive(&self) -> bool { + self.platform + .get_panel_od() + .map_err(|err| { + warn!("CtrlRogBios: get panel overdrive {}", err); + err + }) + .unwrap_or(false) } #[dbus_interface(signal)] @@ -163,9 +163,8 @@ impl crate::Reloadable for CtrlRogBios { impl CtrlRogBios { pub fn new(config: Arc>) -> Result { - if Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists() { - CtrlRogBios::set_path_mutable(ASUS_SWITCH_GRAPHIC_MODE)?; - } else { + let platform = AsusPlatform::new()?; + if !platform.has_gpu_mux_mode() { info!("G-Sync Switchable Graphics not detected"); info!("If your laptop is not a G-Sync enabled laptop then you can ignore this. Standard graphics switching will still work."); } @@ -176,7 +175,10 @@ impl CtrlRogBios { info!("Switch for POST boot sound not detected"); } - Ok(CtrlRogBios { _config: config }) + Ok(CtrlRogBios { + platform, + _config: config, + }) } fn set_path_mutable(path: &str) -> Result<(), RogError> { @@ -189,48 +191,14 @@ impl CtrlRogBios { Ok(()) } - pub fn has_dedicated_gfx_toggle() -> bool { - Path::new(ASUS_SWITCH_GRAPHIC_MODE).exists() - } - - pub fn get_gfx_mode() -> Result { - 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)?; - - let idx = data.len() - 1; - if dedicated { - data[idx] = 1; + pub(super) fn set_gfx_mode(&self, enable: bool) -> Result<(), RogError> { + self.platform.set_gpu_mux_mode(enable)?; + self.update_initramfs(enable)?; + if enable { 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)?; Ok(()) } @@ -358,42 +326,11 @@ impl CtrlRogBios { Ok(()) } - fn set_panel_od(&mut self, overdrive: bool) -> Result<(), RogError> { - let path = ASUS_PANEL_OD_PATH; - let mut file = OpenOptions::new().write(true).open(path).map_err(|err| { - warn!("CtrlRogBios: set_panel_overdrive {}", err); - err - })?; - - let s = if overdrive { '1' } else { '0' }; - file.write(&[s as u8]).map_err(|err| { + fn set_panel_od(&mut self, enable: bool) -> Result<(), RogError> { + self.platform.set_panel_od(enable).map_err(|err| { warn!("CtrlRogBios: set_panel_overdrive {}", err); err })?; Ok(()) } } - -#[cfg(test)] -mod tests { - use super::CtrlRogBios; - use crate::config::Config; - use std::sync::{Arc, Mutex}; - - #[test] - #[ignore = "Must be manually tested"] - fn set_multizone_4key_config() { - let config = Config::default(); - - let controller = CtrlRogBios { - _config: Arc::new(Mutex::new(config)), - }; - - let res = controller.panel_overdrive(); - assert_eq!(res, 1); - - // controller.set_panel_od(false).unwrap(); - // let res = controller.panel_overdrive(); - // assert_eq!(res, 0); - } -} diff --git a/daemon/src/error.rs b/daemon/src/error.rs index 963cab63..04b8556b 100644 --- a/daemon/src/error.rs +++ b/daemon/src/error.rs @@ -1,4 +1,5 @@ use rog_anime::error::AnimeError; +use rog_platform::error::PlatformError; use rog_profiles::error::ProfileError; use std::convert::From; use std::fmt; @@ -28,6 +29,7 @@ pub enum RogError { NoAuraKeyboard, NoAuraNode, Anime(AnimeError), + Platform(PlatformError), } impl fmt::Display for RogError { @@ -57,6 +59,7 @@ impl fmt::Display for RogError { RogError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), RogError::NoAuraNode => write!(f, "No Aura keyboard node found"), RogError::Anime(deets) => write!(f, "AniMe Matrix error: {}", deets), + RogError::Platform(deets) => write!(f, "Asus Platform error: {}", deets), } } } @@ -75,6 +78,12 @@ impl From for RogError { } } +impl From for RogError { + fn from(err: PlatformError) -> Self { + RogError::Platform(err) + } +} + impl From for RogError { fn from(err: zbus::Error) -> Self { RogError::Zbus(err) diff --git a/rog-anime/Cargo.toml b/rog-anime/Cargo.toml index bdd658d5..9cc57dd7 100644 --- a/rog-anime/Cargo.toml +++ b/rog-anime/Cargo.toml @@ -15,7 +15,7 @@ exclude = ["data"] [features] default = ["dbus", "detect"] dbus = ["zvariant", "zbus"] -detect = ["udev", "sysfs-class"] +detect = ["sysfs-class"] [dependencies] png_pong = "^0.8.0" @@ -31,5 +31,4 @@ glam = { version = "^0.21.2", features = ["serde"] } zvariant = { version = "^3.0", optional = true } zbus = { version = "^2.2", optional = true } -udev = { version = "^0.6", optional = true } sysfs-class = { version = "^0.1", optional = true } \ No newline at end of file diff --git a/rog-anime/src/usb.rs b/rog-anime/src/usb.rs index 14e69e74..1541af5d 100644 --- a/rog-anime/src/usb.rs +++ b/rog-anime/src/usb.rs @@ -36,30 +36,6 @@ pub fn get_anime_type() -> Result { Err(AnimeError::UnsupportedDevice) } -/// Find the USB device node - known devices so far: `19b6` -#[inline] -pub fn find_node(id_product: &str) -> Result { - let mut enumerator = - udev::Enumerator::new().map_err(|err| AnimeError::Udev("enumerator failed".into(), err))?; - enumerator - .match_subsystem("usb") - .map_err(|err| AnimeError::Udev("match_subsystem failed".into(), err))?; - - for device in enumerator - .scan_devices() - .map_err(|err| AnimeError::Udev("scan_devices failed".into(), err))? - { - if let Some(attr) = device.attribute_value("idProduct") { - if attr == id_product { - if let Some(dev_node) = device.devnode() { - return Ok(dev_node.to_string_lossy().to_string()); - } - } - } - } - Err(AnimeError::NoDevice) -} - /// Get the two device initialization packets. These are required for device start /// after the laptop boots. #[inline] diff --git a/rog-aura/src/layouts/mod.rs b/rog-aura/src/layouts/mod.rs index 781f27ab..893fad82 100644 --- a/rog-aura/src/layouts/mod.rs +++ b/rog-aura/src/layouts/mod.rs @@ -9,7 +9,7 @@ use crate::{error::Error, keys::Key}; use serde::{Deserialize, Serialize}; use std::{fs::OpenOptions, io::Read, path::Path, slice::Iter}; -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct KeyLayout { /// A series of board names that this layout can be used for. The board names /// stored with the layout can be globbed, e.g, GA401 will match all of the @@ -48,7 +48,7 @@ impl KeyLayout { } } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct KeyRow { height: f32, row: Vec, diff --git a/rog-control-center/src/app.rs b/rog-control-center/src/app.rs index 96d14c09..7c35997f 100644 --- a/rog-control-center/src/app.rs +++ b/rog-control-center/src/app.rs @@ -1,6 +1,5 @@ use std::{ f64::consts::PI, - io::Write, sync::{ atomic::{AtomicBool, AtomicU8, Ordering}, Arc, @@ -12,18 +11,13 @@ use egui::{Button, RichText}; use rog_supported::SupportedFunctions; use crate::{ - config::Config, error::Result, get_ipc_file, page_states::PageDataStates, Page, - RogDbusClientBlocking, SHOWING_GUI, + config::Config, error::Result, page_states::PageDataStates, Page, RogDbusClientBlocking, }; pub struct RogApp<'a> { pub page: Page, pub states: PageDataStates, pub supported: SupportedFunctions, - /// Should the app begin showing the GUI - pub begin_show_gui: Arc, - /// Is the app GUI closed (and running in bg) - pub running_in_bg: bool, // TODO: can probably just open and read whenever pub config: Config, pub asus_dbus: RogDbusClientBlocking<'a>, @@ -40,9 +34,7 @@ pub struct RogApp<'a> { impl<'a> RogApp<'a> { /// Called once before the first frame. pub fn new( - start_closed: bool, config: Config, - show_gui: Arc, states: PageDataStates, _cc: &eframe::CreationContext<'_>, ) -> Result { @@ -99,8 +91,6 @@ impl<'a> RogApp<'a> { supported, states, page: Page::System, - begin_show_gui: show_gui, - running_in_bg: start_closed, config, asus_dbus: dbus, oscillator1, @@ -113,20 +103,10 @@ impl<'a> RogApp<'a> { } impl<'a> eframe::App for RogApp<'a> { - fn on_exit_event(&mut self) -> bool { - if self.config.run_in_background { - self.running_in_bg = true; - get_ipc_file().unwrap().write_all(&[0]).unwrap(); - return false; - } - true - } - /// Called each time the UI needs repainting, which may be many times per second. /// Put your widgets into a `SidePanel`, `TopPanel`, `CentralPanel`, `Window` or `Area`. fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { let Self { - begin_show_gui: should_show_gui, supported, asus_dbus: dbus, states, @@ -144,21 +124,6 @@ impl<'a> eframe::App for RogApp<'a> { let page = self.page; - if should_show_gui.load(Ordering::SeqCst) { - let mut ipc_file = get_ipc_file().unwrap(); - ipc_file.write_all(&[SHOWING_GUI]).unwrap(); - should_show_gui.store(false, Ordering::SeqCst); - frame.set_visible(true); - self.running_in_bg = false; - } - if self.running_in_bg { - // Request to draw nothing at all - ctx.request_repaint_after(Duration::from_millis(500)); - frame.set_visible(false); - return; - } - // Do all GUI display after this point - self.top_bar(ctx, frame); self.side_panel(ctx); diff --git a/rog-control-center/src/lib.rs b/rog-control-center/src/lib.rs index 683fd1f2..dc57453a 100644 --- a/rog-control-center/src/lib.rs +++ b/rog-control-center/src/lib.rs @@ -44,6 +44,14 @@ pub fn on_tmp_dir_exists() -> Result { let mut buf = [0u8; 4]; let path = std::env::temp_dir().join("rog-gui"); + if path.read_dir()?.next().is_none() { + std::fs::remove_dir_all(path)?; + return tempfile::Builder::new() + .prefix("rog-gui") + .rand_bytes(0) + .tempdir(); + } + let mut ipc_file = OpenOptions::new() .read(true) .write(true) diff --git a/rog-control-center/src/main.rs b/rog-control-center/src/main.rs index 1b716aed..7f5028ad 100644 --- a/rog-control-center/src/main.rs +++ b/rog-control-center/src/main.rs @@ -2,19 +2,14 @@ use rog_aura::layouts::KeyLayout; use rog_control_center::{ config::Config, get_ipc_file, notify::start_notifications, on_tmp_dir_exists, page_states::PageDataStates, startup_error::AppErrorShow, RogApp, RogDbusClientBlocking, - SHOW_GUI, + SHOWING_GUI, SHOW_GUI, }; use std::{ fs::{self, OpenOptions}, - io::Read, + io::{Read, Write}, path::PathBuf, - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - thread::spawn, - time::Duration, + sync::{atomic::AtomicBool, Arc}, }; #[cfg(not(feature = "mocking"))] @@ -29,6 +24,7 @@ fn main() -> Result<(), Box> { transparent: false, min_window_size: Some(egui::vec2(840.0, 600.0)), max_window_size: Some(egui::vec2(840.0, 600.0)), + run_and_return: true, ..Default::default() }; @@ -44,7 +40,7 @@ fn main() -> Result<(), Box> { // Startup let mut config = Config::load()?; - let start_closed = config.startup_in_background; + let mut start_closed = config.startup_in_background; if config.startup_in_background { config.run_in_background = true; @@ -94,44 +90,15 @@ fn main() -> Result<(), Box> { let fans_notified = Arc::new(AtomicBool::new(false)); let notifs_enabled = Arc::new(AtomicBool::new(config.enable_notifications)); - let states = { - let supported = dbus - .proxies() - .supported() - .supported_functions() - .map_err(|e| { - eframe::run_native( - "ROG Control Center", - native_options.clone(), - Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))), - ); - }) - .unwrap(); - PageDataStates::new( - layout, - notifs_enabled.clone(), - charge_notified.clone(), - bios_notified.clone(), - aura_notified.clone(), - anime_notified.clone(), - profiles_notified.clone(), - fans_notified.clone(), - &supported, - &dbus, - )? // TODO: if error, show alt GUI containing the error message - }; - - if config.enable_notifications { - start_notifications( - charge_notified, - bios_notified, - aura_notified, - anime_notified, - profiles_notified, - fans_notified, - notifs_enabled, - )?; - } + start_notifications( + charge_notified.clone(), + bios_notified.clone(), + aura_notified.clone(), + anime_notified.clone(), + profiles_notified.clone(), + fans_notified.clone(), + notifs_enabled.clone(), + )?; // tmp-dir must live to the end of program life let _tmp_dir = match tempfile::Builder::new() @@ -143,25 +110,59 @@ fn main() -> Result<(), Box> { Err(_) => on_tmp_dir_exists().unwrap(), }; - let should_show_gui = Arc::new(AtomicBool::new(!start_closed)); - let should = should_show_gui.clone(); - spawn(move || { - // Loop is blocked here until a single byte is read - loop { - let mut buf = [0u8; 4]; - if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI { - should_show_gui.store(true, Ordering::SeqCst); - // Give the starting app a change to read or we'll race it - std::thread::sleep(Duration::from_millis(10)); - } - } - }); + loop { + let states = { + let supported = match dbus.proxies().supported().supported_functions() { + Ok(s) => s, + Err(e) => { + eframe::run_native( + "ROG Control Center", + native_options.clone(), + Box::new(move |_| Box::new(AppErrorShow::new(e.to_string()))), + ); + return Ok(()); + } + }; - eframe::run_native( - "ROG Control Center", - native_options, - Box::new(move |cc| { - Box::new(RogApp::new(start_closed, config, should, states, cc).unwrap()) - }), - ); + PageDataStates::new( + layout.clone(), + notifs_enabled.clone(), + charge_notified.clone(), + bios_notified.clone(), + aura_notified.clone(), + anime_notified.clone(), + profiles_notified.clone(), + fans_notified.clone(), + &supported, + &dbus, + )? + }; + + if !start_closed { + let mut ipc_file = get_ipc_file().unwrap(); + ipc_file.write_all(&[SHOWING_GUI]).unwrap(); + eframe::run_native( + "ROG Control Center", + native_options.clone(), + Box::new(move |cc| { + Box::new(RogApp::new(Config::load().unwrap(), states, cc).unwrap()) + }), + ); + } + + let config = Config::load().unwrap(); + if !config.run_in_background { + break; + } + + let mut buf = [0u8; 4]; + // blocks until it is read, typically the read will happen after a second + // process writes to the IPC (so there is data to actually read) + if get_ipc_file().unwrap().read(&mut buf).is_ok() && buf[0] == SHOW_GUI { + start_closed = false; + continue; + } + dbg!("asda"); + } + Ok(()) } diff --git a/rog-control-center/src/page_states.rs b/rog-control-center/src/page_states.rs index c17e48df..a94249d7 100644 --- a/rog-control-center/src/page_states.rs +++ b/rog-control-center/src/page_states.rs @@ -39,13 +39,13 @@ impl BiosState { } else { false }, - dedicated_gfx: if supported.rog_bios_ctrl.dedicated_gfx { - dbus.proxies().rog_bios().dedicated_graphic_mode()? != 0 + dedicated_gfx: if supported.rog_bios_ctrl.dgpu_only { + dbus.proxies().rog_bios().dedicated_graphic_mode()? } else { false }, panel_overdrive: if supported.rog_bios_ctrl.panel_overdrive { - dbus.proxies().rog_bios().panel_overdrive()? != 0 + dbus.proxies().rog_bios().panel_overdrive()? } else { false }, diff --git a/rog-control-center/src/pages/aura_page.rs b/rog-control-center/src/pages/aura_page.rs index c736d5d6..274774da 100644 --- a/rog-control-center/src/pages/aura_page.rs +++ b/rog-control-center/src/pages/aura_page.rs @@ -1,7 +1,7 @@ use std::{sync::atomic::Ordering, time::Duration}; use egui::Color32; -use rog_aura::AuraModeNum; +use rog_aura::{AuraEffect, AuraModeNum}; use crate::{ widgets::{aura_modes_group, keyboard}, @@ -31,14 +31,14 @@ impl<'a> RogApp<'a> { .aura .modes .get(&states.aura.current_mode) - .unwrap() + .unwrap_or(&AuraEffect::default()) .colour1; let c2 = states .aura .modes .get(&states.aura.current_mode) - .unwrap() + .unwrap_or(&AuraEffect::default()) .colour2; let mut colour = Color32::from_rgb(c1.0, c1.1, c1.2); diff --git a/rog-control-center/src/widgets/fan_graph.rs b/rog-control-center/src/widgets/fan_graph.rs index f1792951..748a8872 100644 --- a/rog-control-center/src/widgets/fan_graph.rs +++ b/rog-control-center/src/widgets/fan_graph.rs @@ -16,20 +16,21 @@ pub fn fan_graphs( ui.separator(); let mut item = |p: Profile, ui: &mut Ui| { - ui.group(|ui|{ - ui.selectable_value(&mut curves.show_curve, p, format!("{p:?}")); - ui.add_enabled_ui(curves.show_curve == p ,|ui| { - ui.selectable_value( - &mut curves.show_graph, - FanCurvePU::CPU, - format!("{:?}", FanCurvePU::CPU), - ); - ui.selectable_value( - &mut curves.show_graph, - FanCurvePU::GPU, - format!("{:?}", FanCurvePU::GPU), - ); - });}); + ui.group(|ui| { + ui.selectable_value(&mut curves.show_curve, p, format!("{p:?}")); + ui.add_enabled_ui(curves.show_curve == p, |ui| { + ui.selectable_value( + &mut curves.show_graph, + FanCurvePU::CPU, + format!("{:?}", FanCurvePU::CPU), + ); + ui.selectable_value( + &mut curves.show_graph, + FanCurvePU::GPU, + format!("{:?}", FanCurvePU::GPU), + ); + }); + }); }; ui.horizontal_wrapped(|ui| { diff --git a/rog-control-center/src/widgets/rog_bios.rs b/rog-control-center/src/widgets/rog_bios.rs index a5f474e4..614ceaaf 100644 --- a/rog-control-center/src/widgets/rog_bios.rs +++ b/rog-control-center/src/widgets/rog_bios.rs @@ -90,7 +90,7 @@ pub fn rog_bios_group( } } - if supported.rog_bios_ctrl.dedicated_gfx { + if supported.rog_bios_ctrl.dgpu_only { if ui .add(egui::Checkbox::new( &mut states.bios.dedicated_gfx, diff --git a/rog-dbus/src/zbus_rogbios.rs b/rog-dbus/src/zbus_rogbios.rs index ae4cbd71..8c42a668 100644 --- a/rog-dbus/src/zbus_rogbios.rs +++ b/rog-dbus/src/zbus_rogbios.rs @@ -27,7 +27,7 @@ use zbus_macros::dbus_proxy; )] trait RogBios { /// DedicatedGraphicMode method - fn dedicated_graphic_mode(&self) -> zbus::Result; + fn dedicated_graphic_mode(&self) -> zbus::Result; /// PostBootSound method fn post_boot_sound(&self) -> zbus::Result; @@ -39,7 +39,7 @@ trait RogBios { fn set_post_boot_sound(&self, on: bool) -> zbus::Result<()>; /// PanelOverdrive method - fn panel_overdrive(&self) -> zbus::Result; + fn panel_overdrive(&self) -> zbus::Result; /// SetPanelOverdrive method fn set_panel_overdrive(&self, overdrive: bool) -> zbus::Result<()>; diff --git a/rog-platform/Cargo.toml b/rog-platform/Cargo.toml new file mode 100644 index 00000000..dc858688 --- /dev/null +++ b/rog-platform/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rog_platform" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "*" +udev = "^0.6" +rusb = "^0.9" +sysfs-class = "^0.1" \ No newline at end of file diff --git a/rog-platform/src/error.rs b/rog-platform/src/error.rs new file mode 100644 index 00000000..9be403da --- /dev/null +++ b/rog-platform/src/error.rs @@ -0,0 +1,51 @@ +use std::fmt; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub enum PlatformError { + ParseVendor, + ParseNum, + Udev(String, std::io::Error), + USB(rusb::Error), + Path(String, std::io::Error), + Read(String, std::io::Error), + Write(String, std::io::Error), + NotSupported, + AttrNotFound(String), + MissingFunction(String), + MissingLedBrightNode(String, std::io::Error), + Io(String, std::io::Error), + NoAuraKeyboard, + NoAuraNode, +} + +impl fmt::Display for PlatformError { + // This trait requires `fmt` with this exact signature. + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + PlatformError::ParseVendor => write!(f, "Parse gfx vendor error"), + PlatformError::ParseNum => write!(f, "Parse number error"), + PlatformError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error), + PlatformError::USB(error) => write!(f, "usb {}", error), + PlatformError::Path(path, error) => write!(f, "Path {}: {}", path, error), + PlatformError::Read(path, error) => write!(f, "Read {}: {}", path, error), + PlatformError::Write(path, error) => write!(f, "Write {}: {}", path, error), + PlatformError::NotSupported => write!(f, "Not supported"), + PlatformError::AttrNotFound(deets) => write!(f, "Attribute not found: {}", deets), + PlatformError::MissingFunction(deets) => write!(f, "Missing functionality: {}", deets), + PlatformError::MissingLedBrightNode(path, error) => write!(f, "Led node at {} is missing, please check you have the required patch or dkms module installed: {}", path, error), + PlatformError::Io(path, detail) => write!(f, "std::io error: {} {}", path, detail), + PlatformError::NoAuraKeyboard => write!(f, "No supported Aura keyboard"), + PlatformError::NoAuraNode => write!(f, "No Aura keyboard node found"), + } + } +} + +impl std::error::Error for PlatformError {} + +impl From for PlatformError { + fn from(err: rusb::Error) -> Self { + PlatformError::USB(err) + } +} diff --git a/rog-platform/src/hid_raw.rs b/rog-platform/src/hid_raw.rs new file mode 100644 index 00000000..916f7985 --- /dev/null +++ b/rog-platform/src/hid_raw.rs @@ -0,0 +1,55 @@ +use std::{fs::OpenOptions, io::Write, path::PathBuf}; + +use log::{info, warn}; + +use crate::error::{PlatformError, Result}; + +#[derive(Debug, PartialEq, PartialOrd)] +pub struct HidRaw(PathBuf); + +impl HidRaw { + pub fn new(id_product: &str) -> Result { + let mut enumerator = udev::Enumerator::new().map_err(|err| { + warn!("{}", err); + PlatformError::Udev("enumerator failed".into(), err) + })?; + + enumerator.match_subsystem("hidraw").map_err(|err| { + warn!("{}", err); + PlatformError::Udev("match_subsystem failed".into(), err) + })?; + + for device in enumerator + .scan_devices() + .map_err(|e| PlatformError::Io("enumerator".to_owned(), e))? + { + if let Some(parent) = device + .parent_with_subsystem_devtype("usb", "usb_device") + .map_err(|e| PlatformError::Io(device.devpath().to_string_lossy().to_string(), e))? + { + if let Some(parent) = parent.attribute_value("idProduct") { + if parent == id_product { + if let Some(dev_node) = device.devnode() { + info!("Using device at: {:?} for LED control", dev_node); + return Ok(Self(dev_node.to_owned())); + } + } + } + } + } + Err(PlatformError::MissingFunction(format!( + "hidraw dev {} not found", + id_product + ))) + } + + pub fn write_bytes(&self, message: &[u8]) -> Result<()> { + let mut file = OpenOptions::new() + .write(true) + .open(&self.0) + .map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e))?; + // println!("write: {:02x?}", &message); + file.write_all(message) + .map_err(|e| PlatformError::Io(self.0.to_string_lossy().to_string(), e)) + } +} diff --git a/rog-platform/src/keyboard_led.rs b/rog-platform/src/keyboard_led.rs new file mode 100644 index 00000000..2aed4a12 --- /dev/null +++ b/rog-platform/src/keyboard_led.rs @@ -0,0 +1,59 @@ +use std::path::PathBuf; + +use log::warn; + +use crate::{ + attr_u8, attr_u8_array, + error::{PlatformError, Result}, + to_device, +}; + +#[derive(Debug, Default, PartialEq, PartialOrd)] +pub struct KeyboardLed(PathBuf); + +impl KeyboardLed { + pub fn new() -> Result { + let mut enumerator = udev::Enumerator::new().map_err(|err| { + warn!("{}", err); + PlatformError::Udev("enumerator failed".into(), err) + })?; + + enumerator.match_subsystem("leds").map_err(|err| { + warn!("{}", err); + PlatformError::Udev("match_subsystem failed".into(), err) + })?; + + enumerator + .match_sysname("asus::kbd_backlight") + .map_err(|err| { + warn!("{}", err); + PlatformError::Udev("match_subsystem failed".into(), err) + })?; + + for device in enumerator.scan_devices().map_err(|err| { + warn!("{}", err); + PlatformError::Udev("scan_devices failed".into(), err) + })? { + return Ok(Self(device.syspath().to_owned())); + } + Err(PlatformError::MissingFunction( + "asus::kbd_backlight not found".into(), + )) + } + + attr_u8!(has_brightness, get_brightness, set_brightness, "brightness"); + + attr_u8_array!( + has_keyboard_rgb_mode, + get_keyboard_rgb_mode, + set_keyboard_rgb_mode, + "kbd_rgb_mode" + ); + + attr_u8_array!( + has_keyboard_rgb_state, + get_keyboard_rgb_state, + set_keyboard_rgb_state, + "kbd_rgb_state" + ); +} diff --git a/rog-platform/src/lib.rs b/rog-platform/src/lib.rs new file mode 100644 index 00000000..ced25557 --- /dev/null +++ b/rog-platform/src/lib.rs @@ -0,0 +1,191 @@ +pub mod error; +pub mod hid_raw; +pub mod keyboard_led; +pub mod platform; +pub mod usb_raw; + +use std::path::Path; + +use error::{PlatformError, Result}; +use udev::Device; + +#[macro_export] +macro_rules! attr_bool { + ($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => { + pub fn $hasser(&self) -> bool { + match to_device(&self.0) { + Ok(p) => crate::has_attr(&p, $attr_name), + Err(_) => false, + } + } + + pub fn $getter(&self) -> Result { + crate::read_attr_bool(&to_device(&self.0)?, $attr_name) + } + + pub fn $setter(&self, value: bool) -> Result<()> { + crate::write_attr_bool(&mut to_device(&self.0)?, $attr_name, value) + } + }; +} + +#[macro_export] +macro_rules! attr_u8 { + ($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => { + pub fn $hasser(&self) -> bool { + match to_device(&self.0) { + Ok(p) => crate::has_attr(&p, $attr_name), + Err(_) => false, + } + } + + pub fn $getter(&self) -> Result { + crate::read_attr_u8(&to_device(&self.0)?, $attr_name) + } + + pub fn $setter(&self, value: u8) -> Result<()> { + crate::write_attr_u8(&mut to_device(&self.0)?, $attr_name, value) + } + }; +} + +#[macro_export] +macro_rules! attr_u8_array { + ($hasser:ident, $getter:ident, $setter:ident, $attr_name:literal) => { + pub fn $hasser(&self) -> bool { + match to_device(&self.0) { + Ok(p) => crate::has_attr(&p, $attr_name), + Err(_) => false, + } + } + + pub fn $getter(&self) -> Result> { + crate::read_attr_u8_array(&to_device(&self.0)?, $attr_name) + } + + pub fn $setter(&self, values: &[u8]) -> Result<()> { + crate::write_attr_u8_array(&mut to_device(&self.0)?, $attr_name, values) + } + }; +} + +pub(crate) fn to_device(sys_path: &Path) -> Result { + Device::from_syspath(sys_path) + .map_err(|e| PlatformError::Udev("Couldn't transform syspath to device".to_string(), e)) +} + +pub fn has_attr(device: &Device, attr_name: &str) -> bool { + for attr in device.attributes() { + if attr.name() == attr_name { + return true; + } + } + false +} + +pub fn read_attr_bool(device: &Device, attr_name: &str) -> Result { + if let Some(value) = device.attribute_value(attr_name) { + let tmp = value.to_string_lossy(); + if tmp.trim() == "0" { + return Ok(false); + } + return Ok(true); + } + Err(PlatformError::AttrNotFound(attr_name.to_string())) +} + +pub fn write_attr_bool(device: &mut Device, attr: &str, value: bool) -> Result<()> { + device + .set_attribute_value(attr, &(value as u8).to_string()) + .map_err(|e| PlatformError::Io(attr.into(), e)) +} + +pub fn read_attr_u8(device: &Device, attr_name: &str) -> Result { + if let Some(value) = device.attribute_value(attr_name) { + let tmp = value.to_string_lossy(); + return Ok(tmp.parse::().map_err(|_| PlatformError::ParseNum)?); + } + Err(PlatformError::AttrNotFound(attr_name.to_string())) +} + +pub fn write_attr_u8(device: &mut Device, attr: &str, value: u8) -> Result<()> { + device + .set_attribute_value(attr, &(value).to_string()) + .map_err(|e| PlatformError::Io(attr.into(), e)) +} + +pub fn read_attr_u8_array(device: &Device, attr_name: &str) -> Result> { + if let Some(value) = device.attribute_value(attr_name) { + let tmp = value.to_string_lossy(); + let tmp = tmp + .split(' ') + .map(|v| u8::from_str_radix(v, 10).unwrap_or(0)) + .collect(); + return Ok(tmp); + } + Err(PlatformError::AttrNotFound(attr_name.to_string())) +} + +pub fn write_attr_u8_array(device: &mut Device, attr: &str, values: &[u8]) -> Result<()> { + let tmp: String = values.iter().map(|v| format!("{} ", v)).collect(); + let tmp = tmp.trim(); + device + .set_attribute_value(attr, &tmp) + .map_err(|e| PlatformError::Io(attr.into(), e)) +} + +#[cfg(test)] +mod tests { + #[test] + fn check() { + let data = [1, 2, 3, 4, 5]; + + let tmp: String = data.iter().map(|v| format!("{} ", v)).collect(); + let tmp = tmp.trim(); + assert_eq!(tmp, "1 2 3 4 5"); + + let tmp: Vec = tmp + .split(' ') + .map(|v| u8::from_str_radix(v, 10).unwrap_or(0)) + .collect(); + assert_eq!(tmp, &[1, 2, 3, 4, 5]); + } +} + +// pub fn find_led_node(id_product: &str) -> Result { +// let mut enumerator = udev::Enumerator::new().map_err(|err| { +// warn!("{}", err); +// PlatformError::Udev("enumerator failed".into(), err) +// })?; +// enumerator.match_subsystem("hidraw").map_err(|err| { +// warn!("{}", err); +// PlatformError::Udev("match_subsystem failed".into(), err) +// })?; + +// for device in enumerator.scan_devices().map_err(|err| { +// warn!("{}", err); +// PlatformError::Udev("scan_devices failed".into(), err) +// })? { +// if let Some(parent) = device +// .parent_with_subsystem_devtype("usb", "usb_device") +// .map_err(|err| { +// warn!("{}", err); +// PlatformError::Udev("parent_with_subsystem_devtype failed".into(), err) +// })? +// { +// if parent +// .attribute_value("idProduct") +// .ok_or_else(|| PlatformError::NotFound("LED idProduct".into()))? +// == id_product +// { +// if let Some(dev_node) = device.devnode() { +// info!("Using device at: {:?} for LED control", dev_node); +// return Ok(device); +// } +// } +// } +// } +// Err(PlatformError::MissingFunction( +// "ASUS LED device node not found".into(), +// )) +// } diff --git a/rog-platform/src/platform.rs b/rog-platform/src/platform.rs new file mode 100644 index 00000000..ceb4bda0 --- /dev/null +++ b/rog-platform/src/platform.rs @@ -0,0 +1,69 @@ +use std::path::PathBuf; + +use log::warn; + +use crate::{ + attr_bool, + error::{PlatformError, Result}, + to_device, +}; + +/// The "platform" device provides access to things like: +/// - dgpu_disable +/// - egpu_enable +/// - panel_od +/// - dgpu_only +/// - keyboard_mode, set keyboard RGB mode and speed +/// - keyboard_state, set keyboard power states +#[derive(Debug, PartialEq, PartialOrd)] +pub struct AsusPlatform(PathBuf); + +impl AsusPlatform { + pub fn new() -> Result { + let mut enumerator = udev::Enumerator::new().map_err(|err| { + warn!("{}", err); + PlatformError::Udev("enumerator failed".into(), err) + })?; + enumerator.match_subsystem("platform").map_err(|err| { + warn!("{}", err); + PlatformError::Udev("match_subsystem failed".into(), err) + })?; + enumerator.match_sysname("asus-nb-wmi").map_err(|err| { + warn!("{}", err); + PlatformError::Udev("match_subsystem failed".into(), err) + })?; + + for device in enumerator.scan_devices().map_err(|err| { + warn!("{}", err); + PlatformError::Udev("scan_devices failed".into(), err) + })? { + return Ok(Self(device.syspath().to_owned())); + } + Err(PlatformError::MissingFunction( + "asus-nb-wmi not found".into(), + )) + } + + attr_bool!( + has_dgpu_disable, + get_dgpu_disable, + set_dgpu_disable, + "dgpu_disable" + ); + + attr_bool!( + has_egpu_enable, + get_egpu_enable, + set_egpu_enable, + "egpu_enable" + ); + + attr_bool!(has_panel_od, get_panel_od, set_panel_od, "panel_od"); + + attr_bool!( + has_gpu_mux_mode, + get_gpu_mux_mode, + set_gpu_mux_mode, + "gpu_mux_mode" + ); +} diff --git a/rog-platform/src/usb_raw.rs b/rog-platform/src/usb_raw.rs new file mode 100644 index 00000000..34b32097 --- /dev/null +++ b/rog-platform/src/usb_raw.rs @@ -0,0 +1,48 @@ +use rusb::{Device, DeviceHandle}; +use std::time::Duration; + +use crate::error::{PlatformError, Result}; + +#[derive(Debug, PartialEq)] +pub struct USBRaw(DeviceHandle); + +impl USBRaw { + pub fn new(id_product: u16) -> Result { + for device in rusb::devices()?.iter() { + let device_desc = device.device_descriptor()?; + if device_desc.vendor_id() == 0x0b05 && device_desc.product_id() == id_product { + let handle = Self::get_dev_handle(device)?; + return Ok(Self(handle)); + } + } + + Err(PlatformError::MissingFunction(format!( + "USBRaw dev {} not found", + id_product + ))) + } + + fn get_dev_handle( + device: Device, + ) -> Result> { + // We don't expect this ID to ever change + let mut device = device.open()?; + device.reset()?; + device.set_auto_detach_kernel_driver(true)?; + device.claim_interface(0)?; + Ok(device) + } + + pub fn write_bytes(&self, message: &[u8]) -> Result { + self.0 + .write_control( + 0x21, // request_type + 0x09, // request + 0x35e, // value + 0x00, // index + message, + Duration::from_millis(200), + ) + .map_err(|e| PlatformError::USB(e)) + } +} diff --git a/rog-supported/src/lib.rs b/rog-supported/src/lib.rs index 4de3f96b..a2ed4cf1 100644 --- a/rog-supported/src/lib.rs +++ b/rog-supported/src/lib.rs @@ -40,7 +40,7 @@ pub struct LedSupportedFunctions { #[derive(Serialize, Deserialize, Type, Debug, Default)] pub struct RogBiosSupportedFunctions { pub post_sound: bool, - pub dedicated_gfx: bool, + pub dgpu_only: bool, pub panel_overdrive: bool, pub dgpu_disable: bool, pub egpu_enable: bool, @@ -95,7 +95,7 @@ impl fmt::Display for RogBiosSupportedFunctions { writeln!(f, "\tPanel Overdrive: {}", self.panel_overdrive)?; writeln!(f, "\tdGPU disable switch: {}", self.dgpu_disable)?; writeln!(f, "\teGPU enable switch: {}", self.egpu_enable)?; - writeln!(f, "\tDedicated GFX switch: {}", self.dedicated_gfx)?; + writeln!(f, "\tDedicated GFX switch: {}", self.dgpu_only)?; Ok(()) } }