Compare commits

...

33 Commits

Author SHA1 Message Date
Denis Benato
e512d0e2a0 fix: do not fail when attributes are unavailable 2026-02-01 16:55:38 +01:00
Denis Benato
8161005096 fix: refresh ppt sliders when power profile gets changed 2026-02-01 16:50:45 +01:00
Denis Benato
ad073c10ff Chore: restore GPU WIP page 2026-01-28 03:57:37 +01:00
Denis Benato
475f321100 Release: 6.3.2 2026-01-28 03:54:09 +01:00
Denis Benato
6330b6b3b0 fix: hide WIP GPU code 2026-01-28 03:48:27 +01:00
Denis Benato
99ec1e8bcf feat: improve the UI 2026-01-27 01:42:19 +01:00
Denis Benato
c2a3310891 fix: move keyboard power 2026-01-27 01:09:02 +01:00
Denis Benato
024d41727f feat: support TUF lighting power 2026-01-26 22:38:07 +01:00
Denis Benato
7d55a2675b feat: reorder CLI parameters 2026-01-26 20:49:41 +01:00
Denis Benato
37fad1741e fix: name the correct power profile 2026-01-26 02:49:30 +01:00
Denis Benato
8867749e0e feat: improve GPU selection 2026-01-26 00:28:26 +01:00
Denis Benato
d890461777 Merge branch 'devel' into 'devel'
feat: add pulse mode to G835L and format file

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

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

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

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

See merge request asus-linux/asusctl!248
2026-01-18 22:15:02 +00:00
Mykola Shevchenko
d4eca0c93e feat: improve toast message for rogcc 2026-01-18 22:15:02 +00:00
52 changed files with 2915 additions and 961 deletions

View File

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

5
.gitignore vendored
View File

@@ -20,3 +20,8 @@ desktop-extensions/gnome*/@types/gir-generated
desktop-extensions/gnome*/node_modules
desktop-extensions/gnome*/schemas/gschemas.compiled
desktop-extensions/gnome*/*.zip
# agents and reference
CLAUDE.md
AGENTS.md
/reference

View File

@@ -1,5 +1,20 @@
# Changelog
## [Unreleased]
### Changes
- Fix PPT sliders not updating
## [6.3.2]
### Changes
- Improve the notification area, @shevchenko0013 strikes again!
- Improve firmware attributes handling
- Very good looking UI restyling from @shevchenko0013
- Added support for GA402NV matrix: thanks @Ghoul4500
- Fixed aura CLI interface
- Fixed LEDs handling in rogcc
## [6.3.1]
### Changes

260
Cargo.lock generated
View File

@@ -212,7 +212,7 @@ dependencies = [
[[package]]
name = "asusctl"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"argh",
"dmi_id",
@@ -232,7 +232,7 @@ dependencies = [
[[package]]
name = "asusd"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"cargo-husky",
"concat-idents",
@@ -259,7 +259,7 @@ dependencies = [
[[package]]
name = "asusd-user"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"config-traits",
"dirs",
@@ -488,7 +488,7 @@ dependencies = [
"num-traits",
"pastey 0.1.1",
"rayon",
"thiserror 2.0.17",
"thiserror 2.0.18",
"v_frame",
"y4m",
]
@@ -816,9 +816,9 @@ checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad"
[[package]]
name = "cc"
version = "1.2.53"
version = "1.2.54"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932"
checksum = "6354c81bbfd62d9cfa9cb3c773c2b7b2a3a482d569de977fd0e961f6e7c00583"
dependencies = [
"find-msvc-tools",
"jobserver",
@@ -938,7 +938,7 @@ dependencies = [
[[package]]
name = "config-traits"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"log",
"ron",
@@ -987,7 +987,7 @@ dependencies = [
[[package]]
name = "const-field-offset"
version = "0.1.5"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"const-field-offset-macro",
"field-offset",
@@ -996,7 +996,7 @@ dependencies = [
[[package]]
name = "const-field-offset-macro"
version = "0.1.5"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"proc-macro2",
"quote",
@@ -1036,16 +1036,6 @@ dependencies = [
"libc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -1059,7 +1049,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081"
dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"core-foundation",
"core-graphics-types",
"foreign-types",
"libc",
@@ -1072,7 +1062,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf"
dependencies = [
"bitflags 1.3.2",
"core-foundation 0.9.4",
"core-foundation",
"libc",
]
@@ -1274,7 +1264,7 @@ dependencies = [
[[package]]
name = "dmi_id"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"log",
"udev 0.8.0",
@@ -1422,9 +1412,9 @@ checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
[[package]]
name = "euclid"
version = "0.22.11"
version = "0.22.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad9cdb4b747e485a12abb0e6566612956c7a1bafa3bdb8d682c5b6d403589e48"
checksum = "df61bf483e837f88d5c2291dcf55c67be7e676b3a51acc48db3a7b163b91ed63"
dependencies = [
"num-traits",
]
@@ -1502,9 +1492,9 @@ dependencies = [
[[package]]
name = "femtovg"
version = "0.19.3"
version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be5d925785ad33d7b0ae2b445d9f157c3ab42ff3c515fff0b46d53d4a86c43c5"
checksum = "a125295d4de2b2473e731c4612599ba3cdf7e05af6bba16f324ba8ffbf093436"
dependencies = [
"bitflags 2.10.0",
"bytemuck",
@@ -1533,14 +1523,13 @@ dependencies = [
[[package]]
name = "filetime"
version = "0.2.26"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed"
checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db"
dependencies = [
"cfg-if",
"libc",
"libredox",
"windows-sys 0.60.2",
]
[[package]]
@@ -1631,7 +1620,7 @@ dependencies = [
"objc2-core-text",
"objc2-foundation 0.3.2",
"read-fonts",
"roxmltree 0.21.1",
"roxmltree",
"smallvec",
"windows 0.58.0",
"windows-core 0.58.0",
@@ -1870,16 +1859,6 @@ dependencies = [
"weezl",
]
[[package]]
name = "gif"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ae047235e33e2829703574b54fdec96bfbad892062d97fed2f76022287de61b"
dependencies = [
"color_quant",
"weezl",
]
[[package]]
name = "gif"
version = "0.14.1"
@@ -2237,7 +2216,7 @@ dependencies = [
"hyper",
"libc",
"pin-project-lite",
"socket2 0.6.1",
"socket2 0.6.2",
"tokio",
"tower-service",
"tracing",
@@ -2246,7 +2225,7 @@ dependencies = [
[[package]]
name = "i-slint-backend-linuxkms"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"calloop 0.14.3",
"drm",
@@ -2264,7 +2243,7 @@ dependencies = [
[[package]]
name = "i-slint-backend-selector"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"cfg-if",
"i-slint-backend-linuxkms",
@@ -2277,7 +2256,7 @@ dependencies = [
[[package]]
name = "i-slint-backend-winit"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"block2 0.6.2",
"cfg-if",
@@ -2316,7 +2295,7 @@ dependencies = [
[[package]]
name = "i-slint-common"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"fontique",
"ttf-parser 0.25.1",
@@ -2325,7 +2304,7 @@ dependencies = [
[[package]]
name = "i-slint-compiler"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"annotate-snippets",
"by_address",
@@ -2353,7 +2332,7 @@ dependencies = [
[[package]]
name = "i-slint-core"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"auto_enums",
"bitflags 2.10.0",
@@ -2388,7 +2367,7 @@ dependencies = [
"slab",
"strum",
"sys-locale",
"thiserror 2.0.17",
"thiserror 2.0.18",
"unicode-linebreak",
"unicode-script",
"unicode-segmentation",
@@ -2396,13 +2375,12 @@ dependencies = [
"wasm-bindgen",
"web-sys",
"web-time",
"webbrowser",
]
[[package]]
name = "i-slint-core-macros"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"quote",
"serde_json",
@@ -2412,7 +2390,7 @@ dependencies = [
[[package]]
name = "i-slint-renderer-femtovg"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"cfg-if",
"const-field-offset",
@@ -2434,7 +2412,7 @@ dependencies = [
[[package]]
name = "i-slint-renderer-skia"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"bytemuck",
"cfg-if",
@@ -2469,7 +2447,7 @@ dependencies = [
[[package]]
name = "i-slint-renderer-software"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"bytemuck",
"clru",
@@ -2633,7 +2611,7 @@ dependencies = [
"rgb",
"tiff",
"zune-core 0.5.1",
"zune-jpeg 0.5.9",
"zune-jpeg 0.5.11",
]
[[package]]
@@ -2648,9 +2626,9 @@ dependencies = [
[[package]]
name = "imagesize"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285"
checksum = "09e54e57b4c48b40f7aec75635392b12b3421fa26fe8b4332e63138ed278459c"
[[package]]
name = "imgref"
@@ -2864,9 +2842,9 @@ dependencies = [
[[package]]
name = "kurbo"
version = "0.11.3"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c62026ae44756f8a599ba21140f350303d4f08dcdcc71b5ad9c9bb8128c13c62"
checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32"
dependencies = [
"arrayvec",
"euclid",
@@ -2875,9 +2853,9 @@ dependencies = [
[[package]]
name = "kurbo"
version = "0.12.0"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce9729cc38c18d86123ab736fd2e7151763ba226ac2490ec092d1dd148825e32"
checksum = "7564e90fe3c0d5771e1f0bc95322b21baaeaa0d9213fa6a0b61c99f8b17b3bfb"
dependencies = [
"arrayvec",
"euclid",
@@ -2924,9 +2902,9 @@ dependencies = [
[[package]]
name = "libm"
version = "0.2.15"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "libredox"
@@ -3244,7 +3222,7 @@ dependencies = [
"objc2-foundation 0.3.2",
"once_cell",
"png 0.17.16",
"thiserror 2.0.17",
"thiserror 2.0.18",
"windows-sys 0.60.2",
]
@@ -3360,9 +3338,9 @@ dependencies = [
[[package]]
name = "num-conv"
version = "0.1.0"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
[[package]]
name = "num-derive"
@@ -4095,9 +4073,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.105"
version = "1.0.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
dependencies = [
"unicode-ident",
]
@@ -4216,9 +4194,9 @@ dependencies = [
[[package]]
name = "quote"
version = "1.0.43"
version = "1.0.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4"
dependencies = [
"proc-macro2",
]
@@ -4318,7 +4296,7 @@ dependencies = [
"rand 0.9.2",
"rand_chacha 0.9.0",
"simd_helpers",
"thiserror 2.0.17",
"thiserror 2.0.18",
"v_frame",
"wasm-bindgen",
]
@@ -4456,11 +4434,11 @@ checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]]
name = "resvg"
version = "0.45.1"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8928798c0a55e03c9ca6c4c6846f76377427d2c1e1f7e6de3c06ae57942df43"
checksum = "b563218631706d614e23059436526d005b50ab5f2d506b55a17eb65c5eb83419"
dependencies = [
"gif 0.13.3",
"gif 0.14.1",
"image-webp",
"log",
"pico-args",
@@ -4468,7 +4446,7 @@ dependencies = [
"svgtypes",
"tiny-skia",
"usvg",
"zune-jpeg 0.4.21",
"zune-jpeg 0.5.11",
]
[[package]]
@@ -4482,7 +4460,7 @@ dependencies = [
[[package]]
name = "rog-control-center"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"asusd",
"concat-idents",
@@ -4513,7 +4491,7 @@ dependencies = [
[[package]]
name = "rog_anime"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"dmi_id",
"gif 0.12.0",
@@ -4527,7 +4505,7 @@ dependencies = [
[[package]]
name = "rog_aura"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"dmi_id",
"log",
@@ -4538,7 +4516,7 @@ dependencies = [
[[package]]
name = "rog_dbus"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"asusd",
"rog_anime",
@@ -4552,7 +4530,7 @@ dependencies = [
[[package]]
name = "rog_platform"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"concat-idents",
"inotify",
@@ -4565,7 +4543,7 @@ dependencies = [
[[package]]
name = "rog_profiles"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"log",
"rog_platform",
@@ -4576,7 +4554,7 @@ dependencies = [
[[package]]
name = "rog_scsi"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"ron",
"serde",
@@ -4586,7 +4564,7 @@ dependencies = [
[[package]]
name = "rog_simulators"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"log",
"rog_anime",
@@ -4596,7 +4574,7 @@ dependencies = [
[[package]]
name = "rog_slash"
version = "6.3.1"
version = "6.3.2"
dependencies = [
"dmi_id",
"serde",
@@ -4629,12 +4607,6 @@ dependencies = [
"text-size",
]
[[package]]
name = "roxmltree"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
[[package]]
name = "roxmltree"
version = "0.21.1"
@@ -4924,9 +4896,9 @@ dependencies = [
[[package]]
name = "siphasher"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "skia-bindings"
@@ -4975,7 +4947,7 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "slint"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"const-field-offset",
"i-slint-backend-selector",
@@ -4995,7 +4967,7 @@ dependencies = [
[[package]]
name = "slint-build"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"derive_more",
"i-slint-compiler",
@@ -5006,7 +4978,7 @@ dependencies = [
[[package]]
name = "slint-macros"
version = "1.15.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"i-slint-compiler",
"proc-macro2",
@@ -5068,7 +5040,7 @@ dependencies = [
"log",
"memmap2",
"rustix 1.1.3",
"thiserror 2.0.17",
"thiserror 2.0.18",
"wayland-backend",
"wayland-client",
"wayland-csd-frame",
@@ -5140,9 +5112,9 @@ dependencies = [
[[package]]
name = "socket2"
version = "0.6.1"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881"
checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0"
dependencies = [
"libc",
"windows-sys 0.60.2",
@@ -5242,11 +5214,11 @@ dependencies = [
[[package]]
name = "svgtypes"
version = "0.15.3"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc"
checksum = "695b5790b3131dafa99b3bbfd25a216edb3d216dad9ca208d4657bfb8f2abc3d"
dependencies = [
"kurbo 0.11.3",
"kurbo 0.13.0",
"siphasher",
]
@@ -5330,7 +5302,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b1e66e07de489fe43a46678dd0b8df65e0c973909df1b60ba33874e297ba9b9"
dependencies = [
"quick-xml 0.37.5",
"thiserror 2.0.17",
"thiserror 2.0.18",
"windows 0.61.3",
"windows-version",
]
@@ -5380,11 +5352,11 @@ dependencies = [
[[package]]
name = "thiserror"
version = "2.0.17"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
dependencies = [
"thiserror-impl 2.0.17",
"thiserror-impl 2.0.18",
]
[[package]]
@@ -5400,9 +5372,9 @@ dependencies = [
[[package]]
name = "thiserror-impl"
version = "2.0.17"
version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [
"proc-macro2",
"quote",
@@ -5434,9 +5406,9 @@ dependencies = [
[[package]]
name = "time"
version = "0.3.45"
version = "0.3.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd"
checksum = "9da98b7d9b7dad93488a84b8248efc35352b0b2657397d4167e7ad67e5d535e5"
dependencies = [
"deranged",
"num-conv",
@@ -5447,9 +5419,9 @@ dependencies = [
[[package]]
name = "time-core"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
[[package]]
name = "tiny-skia"
@@ -5526,7 +5498,7 @@ dependencies = [
"libc",
"mio 1.1.1",
"pin-project-lite",
"socket2 0.6.1",
"socket2 0.6.2",
"tokio-macros",
"tracing",
"windows-sys 0.61.2",
@@ -5940,19 +5912,19 @@ dependencies = [
[[package]]
name = "usvg"
version = "0.45.1"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80be9b06fbae3b8b303400ab20778c80bbaf338f563afe567cf3c9eea17b47ef"
checksum = "e419dff010bb12512b0ae9e3d2f318dfbdf0167fde7eb05465134d4e8756076f"
dependencies = [
"base64 0.22.1",
"data-url",
"flate2",
"fontdb",
"imagesize",
"kurbo 0.11.3",
"kurbo 0.13.0",
"log",
"pico-args",
"roxmltree 0.20.0",
"roxmltree",
"rustybuzz",
"simplecss",
"siphasher",
@@ -5973,9 +5945,9 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]]
name = "uuid"
version = "1.19.0"
version = "1.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a"
checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f"
dependencies = [
"js-sys",
"serde_core",
@@ -6030,7 +6002,7 @@ dependencies = [
[[package]]
name = "vtable"
version = "0.3.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"const-field-offset",
"portable-atomic",
@@ -6041,7 +6013,7 @@ dependencies = [
[[package]]
name = "vtable-macro"
version = "0.3.0"
source = "git+https://github.com/slint-ui/slint.git#75fb4125d8082c5c64b4ce8220c6fe607c8caac0"
source = "git+https://github.com/slint-ui/slint.git#f55d24727b3917ad6953f89a1dd32b48556b290e"
dependencies = [
"proc-macro2",
"quote",
@@ -6296,22 +6268,6 @@ dependencies = [
"wasm-bindgen",
]
[[package]]
name = "webbrowser"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00f1243ef785213e3a32fa0396093424a3a6ea566f9948497e5a2309261a4c97"
dependencies = [
"core-foundation 0.10.1",
"jni",
"log",
"ndk-context",
"objc2 0.6.3",
"objc2-foundation 0.3.2",
"url",
"web-sys",
]
[[package]]
name = "weezl"
version = "0.1.12"
@@ -6933,7 +6889,7 @@ dependencies = [
"calloop 0.13.0",
"cfg_aliases",
"concurrent-queue",
"core-foundation 0.9.4",
"core-foundation",
"core-graphics",
"cursor-icon",
"dpi",
@@ -7152,9 +7108,9 @@ dependencies = [
[[package]]
name = "zbus"
version = "5.13.1"
version = "5.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f79257df967b6779afa536788657777a0001f5b42524fcaf5038d4344df40b"
checksum = "1bfeff997a0aaa3eb20c4652baf788d2dfa6d2839a0ead0b3ff69ce2f9c4bdd1"
dependencies = [
"async-broadcast",
"async-executor",
@@ -7187,9 +7143,9 @@ dependencies = [
[[package]]
name = "zbus_macros"
version = "5.13.1"
version = "5.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aad23e2d2f91cae771c7af7a630a49e755f1eb74f8a46e9f6d5f7a146edf5a37"
checksum = "0bbd5a90dbe8feee5b13def448427ae314ccd26a49cac47905cafefb9ff846f1"
dependencies = [
"proc-macro-crate",
"proc-macro2",
@@ -7219,18 +7175,18 @@ checksum = "6df3dc4292935e51816d896edcd52aa30bc297907c26167fec31e2b0c6a32524"
[[package]]
name = "zerocopy"
version = "0.8.33"
version = "0.8.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd"
checksum = "71ddd76bcebeed25db614f82bf31a9f4222d3fbba300e6fb6c00afa26cbd4d9d"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.33"
version = "0.8.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1"
checksum = "d8187381b52e32220d50b255276aa16a084ec0a9017a0ca2152a1f55c539758d"
dependencies = [
"proc-macro2",
"quote",
@@ -7294,9 +7250,9 @@ dependencies = [
[[package]]
name = "zmij"
version = "1.0.15"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2"
checksum = "02aae0f83f69aafc94776e879363e9771d7ecbffe2c7fbb6c14c5e00dfe88439"
[[package]]
name = "zune-core"
@@ -7330,18 +7286,18 @@ dependencies = [
[[package]]
name = "zune-jpeg"
version = "0.5.9"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87c86acb70a85b2c16f071f171847d1945e8f44812630463cd14ec83900ad01c"
checksum = "2959ca473aae96a14ecedf501d20b3608d2825ba280d5adb57d651721885b0c2"
dependencies = [
"zune-core 0.5.1",
]
[[package]]
name = "zvariant"
version = "5.9.1"
version = "5.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "326aaed414f04fe839777b4c443d4e94c74e7b3621093bd9c5e649ac8aa96543"
checksum = "68b64ef4f40c7951337ddc7023dd03528a57a3ce3408ee9da5e948bd29b232c4"
dependencies = [
"endi",
"enumflags2",
@@ -7353,9 +7309,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "5.9.1"
version = "5.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba44e1f8f4da9e6e2d25d2a60b116ef8b9d0be174a7685e55bb12a99866279a7"
checksum = "484d5d975eb7afb52cc6b929c13d3719a20ad650fea4120e6310de3fc55e415c"
dependencies = [
"proc-macro-crate",
"proc-macro2",

View File

@@ -1,5 +1,5 @@
[workspace.package]
version = "6.3.1"
version = "6.3.2"
rust-version = "1.82"
license = "MPL-2.0"
readme = "README.md"

View File

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

View File

@@ -125,7 +125,7 @@ pub struct AnimeGif {
pub bright: f32,
#[argh(
option,
default = "1",
default = "0",
description = "how many loops to play - 0 is infinite"
)]
pub loops: u32,
@@ -144,7 +144,7 @@ pub struct AnimeGifDiagonal {
pub bright: f32,
#[argh(
option,
default = "1",
default = "0",
description = "how many loops to play - 0 is infinite"
)]
pub loops: u32,

View File

@@ -8,7 +8,7 @@ use rog_aura::{AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed};
#[derive(FromArgs, Debug, Clone)]
#[argh(
subcommand,
name = "aura-power-old",
name = "power-tuf",
description = "aura power (old ROGs and TUF laptops)"
)]
pub struct LedPowerCommand1 {
@@ -38,7 +38,7 @@ pub struct LedPowerCommand1 {
}
#[derive(FromArgs, Debug, Clone)]
#[argh(subcommand, name = "aura-power", description = "aura power")]
#[argh(subcommand, name = "power", description = "aura power")]
pub struct LedPowerCommand2 {
#[argh(subcommand)]
pub command: Option<SetAuraZoneEnabled>,
@@ -312,6 +312,133 @@ pub struct TwoColourSpeed {
pub zone: AuraZone,
}
/// Two-colour star effect (separate subcommand name)
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "stars", description = "two-colour star effect")]
pub struct StarsTwoColour {
#[argh(option, description = "set the first RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the second RGB value e.g. ff00ff")]
pub colour2: Colour,
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Rain effect (single-speed, separate subcommand name)
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "rain",
description = "single speed-based rain effect"
)]
pub struct RainSingleSpeed {
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Laser (single-colour with speed) separate subcommand
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "laser",
description = "single-colour effect with speed"
)]
pub struct LaserSingleColourSpeed {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Ripple (single-colour with speed) separate subcommand
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(
subcommand,
name = "ripple",
description = "single-colour effect with speed"
)]
pub struct RippleSingleColourSpeed {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(option, description = "set the speed: low, med, high")]
pub speed: Speed,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Pulse / Comet / Flash variants (single-colour) separate subcommands
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "pulse", description = "single-colour pulse effect")]
pub struct PulseSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "comet", description = "single-colour comet effect")]
pub struct CometSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
#[derive(FromArgs, Debug, Clone, Default)]
#[argh(subcommand, name = "flash", description = "single-colour flash effect")]
pub struct FlashSingleColour {
#[argh(option, short = 'c', description = "set the RGB value e.g. ff00ff")]
pub colour: Colour,
#[argh(
option,
default = "AuraZone::None",
description = "set the zone for this effect e.g. 0, 1, one, logo, lightbar-left"
)]
pub zone: AuraZone,
}
/// Multi-zone colour settings
#[derive(FromArgs, Debug, Clone, Default)]
#[allow(dead_code)]
@@ -359,14 +486,14 @@ pub enum SetAuraBuiltin {
Breathe(TwoColourSpeed), // 1
RainbowCycle(SingleSpeed), // 2
RainbowWave(SingleSpeedDirection), // 3
Stars(TwoColourSpeed), // 4
Rain(SingleSpeed), // 5
Stars(StarsTwoColour), // 4
Rain(RainSingleSpeed), // 5
Highlight(SingleColourSpeed), // 6
Laser(SingleColourSpeed), // 7
Ripple(SingleColourSpeed), // 8
Pulse(SingleColour), // 10
Comet(SingleColour), // 11
Flash(SingleColour), // 12
Laser(LaserSingleColourSpeed), // 7
Ripple(RippleSingleColourSpeed), // 8
Pulse(PulseSingleColour), // 10
Comet(CometSingleColour), // 11
Flash(FlashSingleColour), // 12
}
impl Default for SetAuraBuiltin {
@@ -428,6 +555,79 @@ impl From<&SingleSpeedDirection> for AuraEffect {
}
}
impl From<&StarsTwoColour> for AuraEffect {
fn from(aura: &StarsTwoColour) -> Self {
Self {
colour1: aura.colour,
colour2: aura.colour2,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&RainSingleSpeed> for AuraEffect {
fn from(aura: &RainSingleSpeed) -> Self {
Self {
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&LaserSingleColourSpeed> for AuraEffect {
fn from(aura: &LaserSingleColourSpeed) -> Self {
Self {
colour1: aura.colour,
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&RippleSingleColourSpeed> for AuraEffect {
fn from(aura: &RippleSingleColourSpeed) -> Self {
Self {
colour1: aura.colour,
speed: aura.speed,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&PulseSingleColour> for AuraEffect {
fn from(aura: &PulseSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&CometSingleColour> for AuraEffect {
fn from(aura: &CometSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&FlashSingleColour> for AuraEffect {
fn from(aura: &FlashSingleColour) -> Self {
Self {
colour1: aura.colour,
zone: aura.zone,
..Default::default()
}
}
}
impl From<&SetAuraBuiltin> for AuraEffect {
fn from(aura: &SetAuraBuiltin) -> Self {
match aura {

View File

@@ -18,9 +18,7 @@ pub struct CliStart {
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum CliCommand {
Aura(LedModeCommand),
AuraPowerOld(LedPowerCommand1),
AuraPower(LedPowerCommand2),
Aura(AuraCommand),
Brightness(BrightnessCommand),
Profile(ProfileCommand),
FanCurve(FanCurveCommand),
@@ -99,7 +97,7 @@ pub struct ProfileSetCommand {
}
#[derive(FromArgs, Debug, Default)]
#[argh(subcommand, name = "aura", description = "led mode commands")]
#[argh(subcommand, name = "effect", description = "led mode commands")]
pub struct LedModeCommand {
#[argh(switch, description = "switch to next aura mode")]
pub next_mode: bool,
@@ -111,6 +109,21 @@ pub struct LedModeCommand {
pub command: Option<SetAuraBuiltin>,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand, name = "aura", description = "aura device commands")]
pub struct AuraCommand {
#[argh(subcommand)]
pub command: AuraSubCommand,
}
#[derive(FromArgs, Debug)]
#[argh(subcommand)]
pub enum AuraSubCommand {
Power(LedPowerCommand2),
PowerTuf(LedPowerCommand1),
Effect(LedModeCommand),
}
#[derive(FromArgs, Debug, Default)]
#[argh(
subcommand,

View File

@@ -186,9 +186,11 @@ fn do_parsed(
conn: Connection,
) -> Result<(), Box<dyn std::error::Error>> {
match &parsed.command {
CliCommand::Aura(mode) => handle_led_mode(mode)?,
CliCommand::AuraPowerOld(pow) => handle_led_power1(pow)?,
CliCommand::AuraPower(pow) => handle_led_power2(pow)?,
CliCommand::Aura(a) => match &a.command {
crate::cli_opts::AuraSubCommand::Effect(mode) => handle_led_mode(mode)?,
crate::cli_opts::AuraSubCommand::PowerTuf(pow) => handle_led_power1(pow)?,
crate::cli_opts::AuraSubCommand::Power(pow) => handle_led_power2(pow)?,
},
CliCommand::Brightness(cmd) => handle_brightness(cmd)?,
CliCommand::Profile(cmd) => handle_throttle_profile(&conn, supported_properties, cmd)?,
CliCommand::FanCurve(cmd) => handle_fan_curve(&conn, cmd)?,
@@ -720,7 +722,7 @@ fn handle_led_power1(power: &LedPowerCommand1) -> Result<(), Box<dyn std::error:
&& !power.keyboard
&& !power.lightbar
{
println!("Missing arg or command; run 'asusctl aura-power-old --help' for usage");
println!("Missing arg or command; run 'asusctl aura power-tuf --help' for usage");
return Ok(());
}
@@ -773,7 +775,7 @@ fn handle_led_power2(power: &LedPowerCommand2) -> Result<(), Box<dyn std::error:
}
if power.command.is_none() {
println!("Missing arg or command; run 'asusctl aura-power --help' for usage");
println!("Missing arg or command; run 'asusctl aura power --help' for usage");
println!("Commands available");
return Ok(());
}
@@ -968,52 +970,72 @@ fn print_firmware_attr(attr: &AsusArmouryProxyBlocking) -> Result<(), Box<dyn st
let name = attr.name()?;
println!("{}:", <&str>::from(name));
let attrs = attr.available_attrs()?;
if attrs.contains(&"min_value".to_string())
&& attrs.contains(&"max_value".to_string())
&& attrs.contains(&"current_value".to_string())
{
let c = attr.current_value()?;
let min = attr.min_value()?;
let max = attr.max_value()?;
println!(" current: {min}..[{c}]..{max}");
if attrs.contains(&"default_value".to_string()) {
println!(" default: {}\n", attr.default_value()?);
// Be resilient to DBus read failures: if any read fails, show "unavailable"
let attrs = attr.available_attrs().unwrap_or_default();
let has_min = attrs.contains(&"min_value".to_string());
let has_max = attrs.contains(&"max_value".to_string());
let has_current = attrs.contains(&"current_value".to_string());
let has_possible = attrs.contains(&"possible_values".to_string());
let has_default = attrs.contains(&"default_value".to_string());
if has_min && has_max && has_current {
let c = attr.current_value().ok();
let min = attr.min_value().ok();
let max = attr.max_value().ok();
match (min, c, max) {
(Some(min), Some(c), Some(max)) => println!(" current: {min}..[{c}]..{max}"),
_ => println!(" current: unavailable"),
}
if has_default {
match attr.default_value().ok() {
Some(d) => println!(" default: {}\n", d),
None => println!(" default: unavailable\n"),
}
} else {
println!();
}
} else if attrs.contains(&"possible_values".to_string())
&& attrs.contains(&"current_value".to_string())
{
let c = attr.current_value()?;
let v = attr.possible_values()?;
for p in v.iter().enumerate() {
if p.0 == 0 {
print!(" current: [");
} else if has_possible && has_current {
let c = attr.current_value().ok();
let v = attr.possible_values().ok();
if let (Some(c), Some(v)) = (c, v) {
for p in v.iter().enumerate() {
if p.0 == 0 {
print!(" current: [");
}
if *p.1 == c {
print!("({c})");
} else {
print!("{}", p.1);
}
if p.0 < v.len() - 1 {
print!(",");
}
if p.0 == v.len() - 1 {
print!("]");
}
}
if *p.1 == c {
print!("({c})");
if has_default {
match attr.default_value().ok() {
Some(d) => println!(" default: {}\n", d),
None => println!(" default: unavailable\n"),
}
} else {
print!("{}", p.1);
println!("\n");
}
if p.0 < v.len() - 1 {
print!(",");
}
if p.0 == v.len() - 1 {
print!("]");
}
}
if attrs.contains(&"default_value".to_string()) {
println!(" default: {}\n", attr.default_value()?);
} else {
println!("\n");
println!(" current: unavailable\n");
}
} else if has_current {
match attr.current_value().ok() {
Some(c) => println!(" current: {c}\n"),
None => println!(" current: unavailable\n"),
}
} else if attrs.contains(&"current_value".to_string()) {
let c = attr.current_value()?;
println!(" current: {c}\n");
} else {
println!();
println!(" unavailable\n");
}
Ok(())
}

View File

@@ -2,7 +2,9 @@ use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_platform::asus_armoury::{AttrValue, Attribute, FirmwareAttribute, FirmwareAttributes};
use rog_platform::asus_armoury::{
AttrValue, Attribute, FirmwareAttribute, FirmwareAttributeType, FirmwareAttributes,
};
use rog_platform::platform::{PlatformProfile, RogPlatform};
use rog_platform::power::AsusPower;
use serde::{Deserialize, Serialize};
@@ -168,82 +170,71 @@ impl ArmouryAttributeRegistry {
impl crate::Reloadable for AsusArmouryAttribute {
async fn reload(&mut self) -> Result<(), RogError> {
info!("Reloading {}", self.attr.name());
let name: FirmwareAttribute = self.attr.name().into();
let attribute: FirmwareAttribute = self.attr.name().into();
let name = self.attr.name();
// Treat dGPU attributes the same as PPT attributes for power-profile
// behaviour so they follow AC/DC tuning groups.
if name.is_ppt() || name.is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
== 1;
let apply_value = {
let config = self.config.lock().await;
config
.select_tunings_ref(power_plugged, profile)
.and_then(|tuning| {
if tuning.enabled {
tuning.group.get(&self.name()).copied()
} else {
None
}
let config = self.config.lock().await;
let apply_value = match attribute.property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
};
.unwrap_or_default()
== 1;
if let Some(tune) = apply_value {
self.attr
.set_current_value(&AttrValue::Integer(tune))
.map_err(|e| {
error!("Could not set {} value: {e:?}", self.attr.name());
self.attr.base_path_exists();
e
})?;
info!(
"Restored PPT armoury setting {} to {:?}",
self.attr.name(),
tune
);
} else {
info!("Ignored restoring PPT armoury setting {} as tuning group is disabled or no saved value", self.attr.name());
let apply_value = {
config.select_tunings_ref(power_plugged, profile).and_then(
|tuning| match tuning.enabled {
true => tuning.group.get(&self.name()).copied(),
false => None,
},
)
};
apply_value.map_or(AttrValue::None, AttrValue::Integer)
}
} else {
// Handle non-PPT attributes (boolean and other settings)
if let Some(saved_value) = self.config.lock().await.armoury_settings.get(&name) {
self.attr
.set_current_value(&AttrValue::Integer(*saved_value))
.map_err(|e| {
error!(
"Error restoring armoury setting {}: {e:?}",
self.attr.name()
);
self.attr.base_path_exists();
e
})?;
FirmwareAttributeType::Gpu => {
info!("Reload called on GPU attribute {name}: doing nothing");
AttrValue::None
}
_ => {
info!("Reload called on firmware attribute {name}");
match config.armoury_settings.get(&attribute) {
Some(saved_value) => AttrValue::Integer(*saved_value),
None => AttrValue::None,
}
}
};
match apply_value {
AttrValue::None => {
info!(
"Restored armoury setting {} to {:?}",
self.attr.name(),
saved_value
);
} else {
info!(
"No saved armoury setting for {}: skipping restore",
"No saved value for attribute {}: skipping.",
self.attr.name()
);
}
_ => {
info!("Applying value {apply_value:?} to attribute {name}");
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set {name} value: {e:?}");
self.attr.base_path_exists();
e
})?;
info!("Restored asus-armoury setting {name} to {apply_value:?}");
}
}
Ok(())
}
}
/// If return is `-1` on a property then there is avilable value for that
/// If return is `-1` on a property then there is available value for that
/// property
#[interface(name = "xyz.ljones.AsusArmoury")]
impl AsusArmouryAttribute {
@@ -293,7 +284,7 @@ impl AsusArmouryAttribute {
async fn restore_default(&self) -> fdo::Result<()> {
self.attr.restore_default()?;
if self.name().is_ppt() || self.name().is_dgpu() {
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -352,7 +343,7 @@ impl AsusArmouryAttribute {
#[zbus(property)]
async fn current_value(&self) -> fdo::Result<i32> {
if self.name().is_ppt() || self.name().is_dgpu() {
if self.name().property_type() == FirmwareAttributeType::Ppt {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -387,66 +378,62 @@ impl AsusArmouryAttribute {
#[zbus(property)]
async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> {
if self.name().is_ppt() || self.name().is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default();
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!("Store tuning config for {} = {:?}", self.attr.name(), value);
}
if tuning.enabled {
self.attr
.set_current_value(&AttrValue::Integer(value))
let name = self.attr.name();
let apply_value = match self.name().property_type() {
FirmwareAttributeType::Ppt => {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!(
"Could not set value to PPT property {}: {e:?}",
self.attr.name()
);
error!("Could not get power status: {e:?}");
e
})?;
} else {
warn!(
"Tuning group is disabled: skipping setting value to PPT property {}",
self.attr.name()
);
}
} else {
self.attr
.set_current_value(&AttrValue::Integer(value))
.map_err(|e| {
error!(
"Could not set value {value} to attribute {}: {e:?}",
self.attr.name()
);
e
})?;
})
.unwrap_or_default();
let mut settings = self.config.lock().await;
settings
.armoury_settings
.entry(self.name())
.and_modify(|setting| {
debug!("Set config for {} = {value}", self.attr.name());
*setting = value;
})
.or_insert_with(|| {
debug!("Adding config for {} = {value}", self.attr.name());
value
});
}
let mut config = self.config.lock().await;
let tuning = config.select_tunings(power_plugged == 1, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!("Store tuning config for {name} = {:?}", value);
}
match tuning.enabled {
true => {
debug!("Tuning is enabled: setting value to PPT property {name} = {value}");
AttrValue::Integer(value)
}
false => {
warn!("Tuning is disabled: skipping setting value to PPT property {name}");
AttrValue::None
}
}
}
_ => {
let mut settings = self.config.lock().await;
settings
.armoury_settings
.entry(self.name())
.and_modify(|setting| {
debug!("Set config for {name} = {value}");
*setting = value;
})
.or_insert_with(|| {
debug!("Adding config for {name} = {value}");
value
});
AttrValue::Integer(value)
}
};
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set value {value} to attribute {name}: {e:?}");
e
})?;
// write config after setting value
self.config.lock().await.write();
@@ -515,7 +502,7 @@ pub async fn set_config_or_default(
) {
for attr in attrs.attributes().iter() {
let name: FirmwareAttribute = attr.name().into();
if name.is_ppt() || name.is_dgpu() {
if name.property_type() == FirmwareAttributeType::Ppt {
let tuning = config.select_tunings(power_plugged, profile);
if !tuning.enabled {
debug!("Tuning group is not enabled, skipping");

View File

@@ -33,7 +33,6 @@ pub struct AuraConfig {
}
impl StdConfig for AuraConfig {
/// Detect the keyboard type and load from default DB if data available
fn new() -> Self {
panic!("This should not be used");
}

View File

@@ -182,7 +182,6 @@ impl AuraZbus {
self.0.set_brightness(config.brightness.into()).await?;
config.set_builtin(effect);
config.write();
Ok(())
}
@@ -208,9 +207,10 @@ impl AuraZbus {
let mut config = self.0.config.lock().await;
for opt in options.states {
let zone = opt.zone;
for config in config.enabled.states.iter_mut() {
if config.zone == zone {
*config = opt;
for state in config.enabled.states.iter_mut() {
if state.zone == zone {
*state = opt;
break;
}
}
}

View File

@@ -196,6 +196,7 @@ impl DeviceHandle {
Some(Arc::new(Mutex::new(k)))
});
// Load saved mode, colours, brightness, power from disk; apply on reload
let mut config = AuraConfig::load_and_update_config(prod_id);
config.led_type = aura_type;
let aura = Aura {

View File

@@ -4,7 +4,9 @@ use std::sync::Arc;
use config_traits::StdConfig;
use log::{debug, error, info, warn};
use rog_platform::asus_armoury::{AttrValue, FirmwareAttribute, FirmwareAttributes};
use rog_platform::asus_armoury::{
AttrValue, FirmwareAttribute, FirmwareAttributeType, FirmwareAttributes,
};
use rog_platform::cpu::{CPUControl, CPUGovernor, CPUEPP};
use rog_platform::platform::{PlatformProfile, Properties, RogPlatform};
use rog_platform::power::AsusPower;
@@ -617,7 +619,7 @@ impl CtrlPlatform {
for attr in self.attributes.attributes() {
let name: FirmwareAttribute = attr.name().into();
if name.is_ppt() {
if name.property_type() == FirmwareAttributeType::Ppt {
// reset stored value
if let Some(tune) = self
.config
@@ -652,6 +654,15 @@ impl CtrlPlatform {
.enabled = enable;
self.config.lock().await.write();
// Re-emit armoury attribute limits so GUI sees updated min/max for PPT
// attributes which can change when enabling/disabling PPT tuning groups.
// Fire-and-forget: we don't want to fail the property call if emit fails.
let _ = self
.armoury_registry
.emit_limits(&self.connection)
.await
.map_err(|e| log::error!("Failed to emit armoury limits: {e:?}"));
Ok(())
}
}
@@ -710,6 +721,13 @@ impl ReloadAndNotify for CtrlPlatform {
*config = data;
config.base_charge_control_end_threshold =
base_charge_control_end_threshold.unwrap_or_default();
// Ensure any armoury limits changes from the new config are emitted
let _ = self
.armoury_registry
.emit_limits(&self.connection)
.await
.map_err(|e| log::error!("Failed to emit armoury limits after reload: {e:?}"));
}
Ok(())
}

View File

@@ -20,7 +20,7 @@
%global debug_package %{nil}
%endif
%define version 6.3.1
%define version 6.3.2
%define specrelease %{?dist}
%define pkg_release 1%{specrelease}

View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

View File

@@ -96,12 +96,17 @@ impl AnimeType {
let board_name = DMIID::new().unwrap_or_default().board_name.to_uppercase();
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
AnimeType::GA401
} else if board_name.contains("GA402R") || board_name.contains("GA402X") {
} else if board_name.contains("GA402R")
|| board_name.contains("GA402X")
|| board_name.contains("GA402N")
{
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604
} else if board_name.contains("G635L") || board_name.contains("G635L") {
} else if board_name.contains("G635L") {
AnimeType::G635L
} else if board_name.contains("G835L") {
AnimeType::G835L
} else {
AnimeType::Unsupported
}
@@ -111,7 +116,9 @@ impl AnimeType {
pub fn width(&self) -> usize {
match self {
AnimeType::GU604 => 70,
AnimeType::G835L => 74,
// TODO: Find G635L W*H
AnimeType::G635L => 68,
AnimeType::G835L => 68,
_ => 74,
}
}
@@ -121,7 +128,8 @@ impl AnimeType {
match self {
AnimeType::GA401 => 36,
AnimeType::GU604 => 43,
AnimeType::G835L => 39,
AnimeType::G635L => 34,
AnimeType::G835L => 34,
_ => 39,
}
}
@@ -130,8 +138,9 @@ impl AnimeType {
pub fn data_length(&self) -> usize {
match self {
AnimeType::GA401 => PANE_LEN * 2,
AnimeType::GU604 => PANE_LEN * 3,
AnimeType::G835L => PANE_LEN * 3,
// G835L has 810 LEDs: 210 (triangle) + 600 (staggered rectangle)
AnimeType::G635L => 810, // TODO: This is provisional until we have a G635L to test on
AnimeType::G835L => 810,
_ => PANE_LEN * 3,
}
}
@@ -195,29 +204,35 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
}
let mut buffers = match anime.anime {
AnimeType::GA401 => vec![[0; 640]; 2],
AnimeType::GA402
| AnimeType::GU604
| AnimeType::G635L
| AnimeType::G835L
| AnimeType::Unsupported => {
AnimeType::GA401 | AnimeType::G635L | AnimeType::G835L => vec![[0; 640]; 2],
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported => {
vec![[0; 640]; 3]
}
};
for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() {
buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk);
// G835L has different packing: 627 bytes in pane 1, 183 bytes in pane 2
if anime.anime == AnimeType::G835L || anime.anime == AnimeType::G635L {
let data = anime.data.as_slice();
// Pane 1: first 627 bytes
let pane1_len = PANE_LEN.min(data.len());
buffers[0][BLOCK_START..BLOCK_START + pane1_len].copy_from_slice(&data[..pane1_len]);
// Pane 2: remaining bytes (183)
if data.len() > PANE_LEN {
let pane2_len = data.len() - PANE_LEN;
buffers[1][BLOCK_START..BLOCK_START + pane2_len].copy_from_slice(&data[PANE_LEN..]);
}
} else {
for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() {
buffers[idx][BLOCK_START..BLOCK_START + chunk.len()].copy_from_slice(chunk);
}
}
buffers[0][..7].copy_from_slice(&USB_PREFIX1);
buffers[1][..7].copy_from_slice(&USB_PREFIX2);
if matches!(
anime.anime,
AnimeType::GA402
| AnimeType::GU604
| AnimeType::G635L
| AnimeType::G835L
| AnimeType::Unsupported
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported
) {
buffers[2][..7].copy_from_slice(&USB_PREFIX3);
}

View File

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

View File

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

View File

@@ -247,7 +247,10 @@ pub fn get_anime_type() -> AnimeType {
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
AnimeType::GA401
} else if board_name.contains("GA402R") || board_name.contains("GA402X") {
} else if board_name.contains("GA402R")
|| board_name.contains("GA402X")
|| board_name.contains("GA402N")
{
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

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

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

View File

@@ -125,7 +125,7 @@
advanced_type: r#None,
power_zones: [Keyboard],
),
(
(
device_name: "FX607V",
product_id: "",
layout_name: "fa506i",
@@ -351,13 +351,13 @@
power_zones: [Keyboard, Lightbar, Logo, RearGlow],
),
(
device_name: "G635L",
product_id: "",
layout_name: "g635l-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
device_name: "G635L",
product_id: "",
layout_name: "g635l-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
),
(
device_name: "G712LI",
@@ -579,7 +579,7 @@
device_name: "G835L",
product_id: "",
layout_name: "g814ji-per-key",
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Comet, Flash],
basic_modes: [Static, Breathe, RainbowCycle, RainbowWave, Star, Rain, Highlight, Laser, Ripple, Pulse, Comet, Flash],
basic_zones: [],
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar, Logo],
@@ -998,4 +998,4 @@
advanced_type: r#None,
power_zones: [Ally],
),
])
])

View File

@@ -148,6 +148,12 @@ async fn main() -> Result<()> {
}
};
let is_tuf = {
let b = board_name.to_lowercase();
let p = prod_family.to_lowercase();
b.contains("tuf") || p.contains("tuf")
};
#[cfg(feature = "rog_ally")]
if is_rog_ally {
config.notifications.enabled = false;
@@ -187,12 +193,18 @@ async fn main() -> Result<()> {
slint::init_translations!(concat!(env!("CARGO_MANIFEST_DIR"), "/translations/"));
}
// Prefetch supported Aura modes once at startup and move into the
// spawned UI thread so the UI uses a stable, immutable list.
let prefetched_supported: std::sync::Arc<Option<Vec<i32>>> = std::sync::Arc::new(
rog_control_center::ui::setup_aura::prefetch_supported_basic_modes().await,
);
thread::spawn(move || {
let mut state = AppState::StartingUp;
loop {
if is_rog_ally {
let config_copy_2 = config.clone();
let newui = setup_window(config.clone());
let newui = setup_window(config.clone(), prefetched_supported.clone(), is_tuf);
newui.window().on_close_requested(move || {
exit(0);
});
@@ -233,6 +245,9 @@ async fn main() -> Result<()> {
let config_copy = config.clone();
let app_state_copy = app_state.clone();
// Avoid moving the original `prefetched_supported` into the
// closure — clone an Arc for the closure to capture.
let pref_for_invoke = prefetched_supported.clone();
slint::invoke_from_event_loop(move || {
UI.with(|ui| {
let app_state_copy = app_state_copy.clone();
@@ -247,7 +262,7 @@ async fn main() -> Result<()> {
});
} else {
let config_copy_2 = config_copy.clone();
let newui = setup_window(config_copy);
let newui = setup_window(config_copy, pref_for_invoke.clone(), is_tuf);
newui.window().on_close_requested(move || {
if let Ok(mut app_state) = app_state_copy.lock() {
*app_state = AppState::MainWindowClosed;

View File

@@ -1,9 +1,14 @@
pub mod setup_anime;
pub mod setup_aura;
pub mod setup_fans;
pub mod setup_gpu;
pub mod setup_system;
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;
static TOAST_SEQ: AtomicU64 = AtomicU64::new(0);
use config_traits::StdConfig;
use log::warn;
@@ -70,25 +75,61 @@ pub fn show_toast(
handle: Weak<MainWindow>,
result: zbus::Result<()>,
) {
// bump sequence so that any previously spawned timers won't clear newer toasts
let seq = TOAST_SEQ.fetch_add(1, Ordering::SeqCst) + 1;
match result {
Ok(_) => {
slint::invoke_from_event_loop(move || handle.unwrap().invoke_show_toast(success)).ok()
let delayed_handle = handle.clone();
let delayed_text = success.clone();
slint::invoke_from_event_loop(move || handle.unwrap().invoke_show_toast(success)).ok();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(5)).await;
if TOAST_SEQ.load(Ordering::SeqCst) == seq {
slint::invoke_from_event_loop(move || {
delayed_handle
.unwrap()
.invoke_clear_toast_if_matches(delayed_text)
})
.ok();
}
});
}
Err(e) => {
let delayed_handle = handle.clone();
let delayed_text = fail.clone();
slint::invoke_from_event_loop(move || {
log::warn!("{fail}: {e}");
handle.unwrap().invoke_show_toast(fail)
})
.ok();
tokio::spawn(async move {
tokio::time::sleep(Duration::from_secs(5)).await;
if TOAST_SEQ.load(Ordering::SeqCst) == seq {
slint::invoke_from_event_loop(move || {
delayed_handle
.unwrap()
.invoke_clear_toast_if_matches(delayed_text)
})
.ok();
}
});
}
Err(e) => slint::invoke_from_event_loop(move || {
log::warn!("{fail}: {e}");
handle.unwrap().invoke_show_toast(fail)
})
.ok(),
};
}
pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
pub fn setup_window(
config: Arc<Mutex<Config>>,
prefetched_supported: std::sync::Arc<Option<Vec<i32>>>,
is_tuf: bool,
) -> MainWindow {
slint::set_xdg_app_id("rog-control-center")
.map_err(|e| warn!("Couldn't set application ID: {e:?}"))
.ok();
let ui = MainWindow::new()
.map_err(|e| warn!("Couldn't create main window: {e:?}"))
.unwrap();
// propagate TUF flag to the UI so the sidebar can swap logo branding
ui.set_is_tuf(is_tuf);
ui.window()
.show()
.map_err(|e| warn!("Couldn't show main window: {e:?}"))
@@ -102,8 +143,9 @@ pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
available.contains(&"xyz.ljones.Aura".to_string()),
available.contains(&"xyz.ljones.Anime".to_string()),
available.contains(&"xyz.ljones.FanCurves".to_string()),
true,
true,
true, // GPU Configuration
true, // App Settings
true, // About
]
.into(),
);
@@ -118,15 +160,18 @@ pub fn setup_window(config: Arc<Mutex<Config>>) -> MainWindow {
setup_system_page_callbacks(&ui, config.clone());
}
if available.contains(&"xyz.ljones.Aura".to_string()) {
setup_aura_page(&ui, config.clone());
setup_aura_page(&ui, config.clone(), prefetched_supported.as_ref().clone());
}
if available.contains(&"xyz.ljones.Anime".to_string()) {
setup_anime_page(&ui, config.clone());
}
if available.contains(&"xyz.ljones.FanCurves".to_string()) {
setup_fan_curve_page(&ui, config);
setup_fan_curve_page(&ui, config.clone());
}
// Populate GPU page choices and callbacks
setup_gpu::setup_gpu_page(&ui);
ui
}

View File

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

View File

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

View File

@@ -40,10 +40,6 @@ pub fn setup_system_page(ui: &MainWindow, _config: Arc<Mutex<Config>>) {
ui.global::<SystemPageData>().set_platform_profile(-1);
ui.global::<SystemPageData>().set_panel_overdrive(-1);
ui.global::<SystemPageData>().set_boot_sound(-1);
ui.global::<SystemPageData>().set_kbd_leds_awake(-1);
ui.global::<SystemPageData>().set_kbd_leds_sleep(-1);
ui.global::<SystemPageData>().set_kbd_leds_boot(-1);
ui.global::<SystemPageData>().set_kbd_leds_shutdown(-1);
ui.global::<SystemPageData>().set_screen_auto_brightness(-1);
ui.global::<SystemPageData>().set_mcu_powersave(-1);
ui.global::<SystemPageData>().set_mini_led_mode(-1);
@@ -673,26 +669,6 @@ pub fn setup_system_page_callbacks(ui: &MainWindow, _states: Arc<Mutex<Config>>)
setup_callback!(boot_sound, handle, attr, i32);
setup_external!(boot_sound, i32, handle, attr, value)
}
FirmwareAttribute::KbdLedsAwake => {
init_property!(kbd_leds_awake, handle, value, i32);
setup_callback!(kbd_leds_awake, handle, attr, i32);
setup_external!(kbd_leds_awake, i32, handle, attr, value)
}
FirmwareAttribute::KbdLedsSleep => {
init_property!(kbd_leds_sleep, handle, value, i32);
setup_callback!(kbd_leds_sleep, handle, attr, i32);
setup_external!(kbd_leds_sleep, i32, handle, attr, value)
}
FirmwareAttribute::KbdLedsBoot => {
init_property!(kbd_leds_boot, handle, value, i32);
setup_callback!(kbd_leds_boot, handle, attr, i32);
setup_external!(kbd_leds_boot, i32, handle, attr, value)
}
FirmwareAttribute::KbdLedsShutdown => {
init_property!(kbd_leds_shutdown, handle, value, i32);
setup_callback!(kbd_leds_shutdown, handle, attr, i32);
setup_external!(kbd_leds_shutdown, i32, handle, attr, value)
}
FirmwareAttribute::ScreenAutoBrightness => {
init_property!(screen_auto_brightness, handle, value, i32);
setup_callback!(screen_auto_brightness, handle, attr, i32);

View File

@@ -7,6 +7,7 @@ import { PageFans } from "pages/fans.slint";
import { PageAnime, AnimePageData } from "pages/anime.slint";
import { RogItem } from "widgets/common.slint";
import { PageAura } from "pages/aura.slint";
import { PageGPU, GPUPageData } from "pages/gpu.slint";
import { Node } from "widgets/graph.slint";
export { Node }
import { FanPageData, FanType, Profile } from "types/fan_types.slint";
@@ -15,7 +16,7 @@ import { AuraPageData, AuraDevType, LaptopAuraPower, AuraPowerState, PowerZones,
export { AuraPageData, AuraDevType, LaptopAuraPower, AuraPowerState, PowerZones, AuraEffect }
import { PageAppSettings, AppSettingsPageData } from "pages/app_settings.slint";
export { AppSize, AttrMinMax, SystemPageData, AnimePageData, AppSettingsPageData }
export { AppSize, AttrMinMax, SystemPageData, AnimePageData, AppSettingsPageData, GPUPageData }
export component MainWindow inherits Window {
title: "ROG Control";
@@ -24,8 +25,18 @@ export component MainWindow inherits Window {
default-font-size: 14px;
default-font-weight: 400;
icon: @image-url("../data/rog-control-center.png");
in property <[bool]> sidebar_items_avilable: [true, true, true, true, true, true];
in property <[bool]> sidebar_items_avilable: [
true,
true,
true,
true,
true, // GPU Configuration
true, // App Settings
true, // About
];
private property <bool> show_notif;
// TODO: change if TUF on the logo in the menu on the main page
in property <bool> is_tuf: false;
private property <bool> fade_cover;
private property <bool> toast: false;
private property <string> toast_text: "I show when something is waiting";
@@ -34,6 +45,13 @@ export component MainWindow inherits Window {
toast = text != "";
toast_text = text;
}
callback clear_toast_if_matches(string);
clear_toast_if_matches(text) => {
if (toast && toast_text == text) {
toast = false;
toast_text = "";
}
}
callback exit-app();
callback show_notification(bool);
show_notification(yes) => {
@@ -47,37 +65,32 @@ export component MainWindow inherits Window {
}
min-height: AppSize.height;
min-width: AppSize.width;
background: Colors.black;
background: Palette.alternate-background;
HorizontalLayout {
padding: 0px;
VerticalLayout {
padding: 0px;
side-bar := SideBar {
title: @tr("ROG");
model: [
@tr("Menu1" => "System Control"),
@tr("Menu2" => "Keyboard Aura"),
@tr("Menu3" => "AniMe Matrix"),
@tr("Menu4" => "Fan Curves"),
@tr("Menu5" => "App Settings"),
@tr("Menu6" => "About"),
@tr("Menu5" => "GPU Configuration"),
@tr("Menu6" => "App Settings"),
@tr("Menu7" => "About"),
];
available: root.sidebar_items_avilable;
is_tuf: root.is_tuf;
}
Rectangle {
max-height: 40px;
Button {
height: 40px;
width: side-bar.width;
background: Palette.control-background;
Text {
vertical-alignment: center;
horizontal-alignment: center;
text: @tr("Quit App");
}
TouchArea {
clicked => {
root.exit-app();
}
text: @tr("Quit App");
clicked() => {
root.exit-app();
}
}
}
@@ -89,26 +102,67 @@ export component MainWindow inherits Window {
height: root.height + 12px;
}
aura := PageAura {
/*if(side-bar.current-item == 1):*/ aura := PageAura {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 1;
}
if(side-bar.current-item == 2): PageAnime {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 2;
}
fans := PageFans {
if(side-bar.current-item == 3): fans := PageFans {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 3;
}
if(side-bar.current-item == 4): PageAppSettings {
if(side-bar.current-item == 4): PageGPU {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 4;
}
if(side-bar.current-item == 5): PageAbout {
if(side-bar.current-item == 5): PageAppSettings {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 5;
}
if(side-bar.current-item == 6): PageAbout {
width: root.width - side-bar.width;
height: root.height + 12px;
visible: side-bar.current-item == 6;
}
if toast: Rectangle {
x: 0px;
y: root.height - self.height;
width: root.width - side-bar.width;
height: 40px;
opacity: 1.0;
background: Palette.selection-background;
clip: true;
TouchArea {
height: 100%;
width: 100%;
clicked => {
toast = false;
}
}
Rectangle {
height: 100%;
width: 100%;
background: Palette.control-background;
Text {
color: Palette.control-foreground;
text: root.toast_text;
}
}
}
}
}
@@ -133,31 +187,6 @@ export component MainWindow inherits Window {
}
}
if toast: Rectangle {
x: 0px;
y: 0px;
width: root.width;
height: 32px;
opacity: 1.0;
background: Colors.grey;
TouchArea {
height: 100%;
width: 100%;
clicked => {
toast = false;
}
}
Rectangle {
height: 100%;
width: 100%;
background: Palette.control-background;
Text {
color: Palette.control-foreground;
text: root.toast_text;
}
}
}
// // TODO: or use Dialogue
if show_notif: Rectangle {
@@ -190,10 +219,6 @@ export component MainWindow inherits Window {
y: 0px;
width: root.width;
height: root.height;
//padding only has effect on layout elements
//padding: 10px;
background: Palette.background;
border-color: Palette.border;
border-width: 3px;

View File

@@ -1,62 +1,77 @@
import { AboutSlint, VerticalBox, HorizontalBox } from "std-widgets.slint";
import {
AboutSlint,
VerticalBox,
HorizontalBox,
ScrollView,
} from "std-widgets.slint";
export component PageAbout inherits VerticalLayout {
padding: 10px;
spacing: 10px;
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "A UI for asusctl made with slint";
font-size: 22px;
}
ScrollView {
HorizontalBox {
alignment: LayoutAlignment.center;
VerticalBox {
HorizontalBox {
alignment: LayoutAlignment.center;
VerticalBox {
alignment: LayoutAlignment.center;
Text {
wrap: TextWrap.word-wrap;
text: "You need to use kernel version 6.19 to use this software";
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "ROG Control Center";
font-size: 22px;
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "Todo:";
font-size: 22px;
}
Text {
wrap: TextWrap.word-wrap;
text: "\nA powerful graphical interface for managing ASUS ROG, TUF, and ProArt laptops on Linux. It acts as the official GUI for the asusctl toolset, allowing for seamless hardware tuning without the command line.";
}
Text {
text: "- [ ] Theme the widgets";
}
Text {
font-weight: 900;
text: "Key Features:";
}
Text {
text: "- [ ] Add a cpu/gpu temp/fan speed info bar";
}
Text {
text: " • Performance: Switch power profiles and customize fan curves.\n • Aura Sync: Control keyboard backlighting and LED effects.\n • Battery Health: Set charge limits to extend battery longevity.\n • Display: Toggle Panel Overdrive and refresh rates.\n • AniMe Matrix: Control AniMe Matrix displays.";
}
Text {
text: "- [ ] Include fan speeds, temps in a bottom bar";
}
Text {
font-weight: 900;
text: "Requirements:";
}
Text {
text: "- [ ] Slash control";
}
Text {
text: " • This software requires kernel version 6.19.";
}
Text {
text: "- [ ] Screenpad controls";
}
Text {
font-weight: 900;
text: "Work in progress:";
}
Text {
text: "- [ ] ROG Ally specific settings";
Text {
text: " • Theme the widgets\n • Add a cpu/gpu temp/fan speed info bar\n • Include fan speeds, temps in a bottom bar\n • Slash control\n • Screenpad controls\n • ROG Ally specific settings";
}
Text {
font-weight: 900;
text: "License:";
}
Text {
text: " This project is open-source software licensed under the Mozilla Public License 2.0 (MPL-2.0).";
}
Text {
font-weight: 900;
text: "Links:";
}
Text {
text: " Source Code: https://gitlab.com/asus-linux/asusctl\n Website: https://asus-linux.org/";
}
}
}
}
Text {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
text: "Work in progress";
font-size: 22px;
}
}

View File

@@ -36,12 +36,8 @@ export component PageAnime inherits Rectangle {
property <bool> show_display_advanced: false;
property <bool> show_builtin_advanced: false;
clip: true;
// TODO: slow with border-radius
//padding only has effect on layout elements
//padding: 8px;
// height: parent.height - infobar.height - mainview.padding - self.padding * 2;
// TODO: border-radius: 8px;
VerticalLayout {
VerticalLayout {
padding: 10px;
spacing: 10px;
HorizontalLayout {
@@ -132,8 +128,9 @@ export component PageAnime inherits Rectangle {
width: 100%;
height: 100%;
opacity: 1;
background: Palette.background;
VerticalLayout {
padding: 50px;
padding: 4px;
spacing: 10px;
GroupBox {
height: 10px;
@@ -141,7 +138,7 @@ export component PageAnime inherits Rectangle {
spacing: 10px;
alignment: LayoutAlignment.start;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Set which builtin animations are played");
@@ -193,8 +190,8 @@ export component PageAnime inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_builtin_advanced = false;
root.show_fade_cover = false;
@@ -206,8 +203,9 @@ export component PageAnime inherits Rectangle {
width: 100%;
height: 100%;
opacity: 1;
background: Palette.background;
VerticalLayout {
padding: 50px;
padding: 4px;
spacing: 10px;
GroupBox {
height: 100px;
@@ -215,7 +213,7 @@ export component PageAnime inherits Rectangle {
spacing: 10px;
alignment: LayoutAlignment.start;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Advanced Display Settings");
@@ -254,8 +252,8 @@ export component PageAnime inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 36px;
clicked => {
root.show_display_advanced = false;
root.show_fade_cover = false;

View File

@@ -15,12 +15,7 @@ export global AppSettingsPageData {
export component PageAppSettings inherits VerticalLayout {
Rectangle {
clip: true;
// TODO: slow with border-radius
//padding only has effect on layout elements
//padding: 8px;
// height: parent.height - infobar.height - mainview.padding - self.padding * 2;
// TODO: border-radius: 8px;
mainview := VerticalLayout {
padding: 10px;
spacing: 10px;
@@ -57,7 +52,8 @@ export component PageAppSettings inherits VerticalLayout {
}
Text {
text: "WIP: some features like notifications are not complete";
color: Palette.accent-background;
text: " WIP: some features like notifications are not complete";
}
}
}

View File

@@ -17,6 +17,7 @@ export component PageAura inherits Rectangle {
c2.final_colour = AuraPageData.led_mode_data.colour2;
c2.external_colour_change();
}
ScrollView {
VerticalLayout {
padding: 10px;
@@ -41,10 +42,14 @@ export component PageAura inherits Rectangle {
current_value: AuraPageData.available_mode_names[self.current-index];
model <=> AuraPageData.available_mode_names;
selected => {
AuraPageData.led_mode_data.mode = AuraPageData.led_mode;
AuraPageData.led_mode_data.mode = AuraPageData.current_available_mode;
self.current_value = AuraPageData.available_mode_names[self.current-index];
AuraPageData.cb_led_mode(AuraPageData.current_available_mode);
AuraPageData.apply_effect({
mode: AuraPageData.supported_basic_modes[self.current-index],
zone: AuraPageData.led_mode_data.zone,
colour1: AuraPageData.led_mode_data.colour1,
colour2: AuraPageData.led_mode_data.colour2,
speed: AuraPageData.led_mode_data.speed,
direction: AuraPageData.led_mode_data.direction,
});
}
}
}
@@ -53,6 +58,7 @@ export component PageAura inherits Rectangle {
min-height: 220px;
max-height: 400px;
HorizontalLayout {
padding-top: 5px;
spacing: 10px;
VerticalBox {
Text {
@@ -60,47 +66,44 @@ export component PageAura inherits Rectangle {
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
}
HorizontalBox {
c1 := ColourSlider {
enabled: AuraPageData.led_mode == 0 || AuraPageData.led_mode == 1 || AuraPageData.led_mode == 4 || AuraPageData.led_mode == 6 || AuraPageData.led_mode == 7 || AuraPageData.led_mode == 8 || AuraPageData.led_mode == 10 || AuraPageData.led_mode == 11 || AuraPageData.led_mode == 12;
enabled: AuraPageData.colour1_enabled;
final_colour <=> AuraPageData.color1;
colourbox <=> AuraPageData.colorbox1;
set_hex_from_colour(c1) => {
return AuraPageData.cb_hex_from_colour(c1);
}
hex_to_colour(s) => {
return AuraPageData.cb_hex_to_colour(s);
}
set_hex_from_colour(c) => { return AuraPageData.cb_hex_from_colour(c); }
hex_to_colour(s) => { return AuraPageData.cb_hex_to_colour(s); }
released => {
AuraPageData.led_mode_data.colour1 = AuraPageData.color1;
AuraPageData.cb_led_mode_data(AuraPageData.led_mode_data);
AuraPageData.apply_effect({
mode: AuraPageData.led_mode_data.mode,
zone: AuraPageData.led_mode_data.zone,
colour1: AuraPageData.color1,
colour2: AuraPageData.led_mode_data.colour2,
speed: AuraPageData.led_mode_data.speed,
direction: AuraPageData.led_mode_data.direction,
});
}
}
}
}
VerticalBox {
Text {
text: @tr("Colour 2");
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text { text: @tr("Colour 2"); vertical-alignment: TextVerticalAlignment.center; horizontal-alignment: TextHorizontalAlignment.center; }
HorizontalBox {
c2 := ColourSlider {
enabled: AuraPageData.led_mode == 1 || AuraPageData.led_mode == 4;
enabled: AuraPageData.colour2_enabled;
final_colour <=> AuraPageData.color2;
colourbox <=> AuraPageData.colorbox2;
set_hex_from_colour(c1) => {
return AuraPageData.cb_hex_from_colour(c1);
}
hex_to_colour(s) => {
return AuraPageData.cb_hex_to_colour(s);
}
set_hex_from_colour(c) => { return AuraPageData.cb_hex_from_colour(c); }
hex_to_colour(s) => { return AuraPageData.cb_hex_to_colour(s); }
released => {
AuraPageData.led_mode_data.colour2 = AuraPageData.color2;
AuraPageData.cb_led_mode_data(AuraPageData.led_mode_data);
AuraPageData.apply_effect({
mode: AuraPageData.led_mode_data.mode,
zone: AuraPageData.led_mode_data.zone,
colour1: AuraPageData.led_mode_data.colour1,
colour2: AuraPageData.color2,
speed: AuraPageData.led_mode_data.speed,
direction: AuraPageData.led_mode_data.direction,
});
}
}
}
@@ -113,70 +116,64 @@ export component PageAura inherits Rectangle {
min-height: 80px;
max-height: 90px;
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Zone");
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text { text: @tr("Zone"); vertical-alignment: TextVerticalAlignment.center; horizontal-alignment: TextHorizontalAlignment.center; }
ComboBox {
// enabled: AuraPageData.led_mode == ;
enabled: false;
enabled: false;
current_index <=> AuraPageData.zone;
current_value: AuraPageData.zone_names[self.current-index];
model <=> AuraPageData.zone_names;
selected => {
AuraPageData.led_mode_data.zone = self.current-index;
AuraPageData.cb_led_mode_data(AuraPageData.led_mode_data);
AuraPageData.apply_effect({
mode: AuraPageData.led_mode_data.mode,
zone: self.current-index,
colour1: AuraPageData.led_mode_data.colour1,
colour2: AuraPageData.led_mode_data.colour2,
speed: AuraPageData.led_mode_data.speed,
direction: AuraPageData.led_mode_data.direction,
});
}
}
}
}
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Direction");
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text { text: @tr("Direction"); vertical-alignment: TextVerticalAlignment.center; horizontal-alignment: TextHorizontalAlignment.center; }
ComboBox {
enabled: AuraPageData.led_mode == 3;
enabled: AuraPageData.direction_enabled;
current_index <=> AuraPageData.direction;
current_value: AuraPageData.direction_names[self.current-index];
model <=> AuraPageData.direction_names;
selected => {
AuraPageData.led_mode_data.direction = self.current-index;
AuraPageData.cb_led_mode_data(AuraPageData.led_mode_data);
AuraPageData.apply_effect({
mode: AuraPageData.led_mode_data.mode,
zone: AuraPageData.led_mode_data.zone,
colour1: AuraPageData.led_mode_data.colour1,
colour2: AuraPageData.led_mode_data.colour2,
speed: AuraPageData.led_mode_data.speed,
direction: self.current-index,
});
}
}
}
}
RogItem {
//padding only has effect on layout elements
//padding: 0px;
VerticalBox {
Text {
text: @tr("Speed");
vertical-alignment: TextVerticalAlignment.center;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text { text: @tr("Speed"); vertical-alignment: TextVerticalAlignment.center; horizontal-alignment: TextHorizontalAlignment.center; }
ComboBox {
enabled: AuraPageData.led_mode == 1 || AuraPageData.led_mode == 2 || AuraPageData.led_mode == 3 || AuraPageData.led_mode == 4 || AuraPageData.led_mode == 5 || AuraPageData.led_mode == 6 || AuraPageData.led_mode == 7 || AuraPageData.led_mode == 8;
enabled: AuraPageData.speed_enabled;
current_index <=> AuraPageData.speed;
current_value: AuraPageData.speed_names[self.current-index];
model <=> AuraPageData.speed_names;
selected => {
AuraPageData.led_mode_data.speed = self.current-index;
AuraPageData.cb_led_mode_data(AuraPageData.led_mode_data);
AuraPageData.apply_effect({
mode: AuraPageData.led_mode_data.mode,
zone: AuraPageData.led_mode_data.zone,
colour1: AuraPageData.led_mode_data.colour1,
colour2: AuraPageData.led_mode_data.colour2,
speed: self.current-index,
direction: AuraPageData.led_mode_data.direction,
});
}
}
}
@@ -205,6 +202,7 @@ export component PageAura inherits Rectangle {
}
if root.show_aura_power && AuraPageData.device_type == AuraDevType.New: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
@@ -240,21 +238,54 @@ export component PageAura inherits Rectangle {
}
}
}
}
}
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
clicked => {
root.show_aura_power = false;
root.show_fade_cover = false;
// TUF devices: show the same configurable power groups as `New`, since
// `setup_aura` fills `AuraPageData.supported_power_zones` and `led_power`
// appropriately for TUF devices. This ensures the Power Settings panel
// reflects what the firmware reports for TUF models.
if root.show_aura_power && AuraPageData.device_type == AuraDevType.Tuf: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
ScrollView {
VerticalLayout {
padding: 30px;
padding-top: 10px;
spacing: 10px;
alignment: LayoutAlignment.start;
for state[idx] in AuraPageData.led_power.states: tuf_zone := AuraPowerGroup {
group-title: AuraPageData.power_zone_names[state.zone_name_idx];
boot_checked: state.boot;
boot_toggled => {
AuraPageData.led_power.states[idx].boot = tuf_zone.boot_checked;
AuraPageData.cb_led_power(AuraPageData.led_power);
}
awake_checked: state.awake;
awake_toggled => {
AuraPageData.led_power.states[idx].awake = tuf_zone.awake_checked;
AuraPageData.cb_led_power(AuraPageData.led_power);
}
sleep_checked: state.sleep;
sleep_toggled => {
AuraPageData.led_power.states[idx].sleep = tuf_zone.sleep_checked;
AuraPageData.cb_led_power(AuraPageData.led_power);
}
shutdown_checked: state.shutdown;
shutdown_toggled => {
AuraPageData.led_power.states[idx].shutdown = tuf_zone.shutdown_checked;
AuraPageData.cb_led_power(AuraPageData.led_power);
}
}
}
}
}
if root.show_aura_power && AuraPageData.device_type == AuraDevType.Old: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
@@ -293,17 +324,17 @@ export component PageAura inherits Rectangle {
}
}
}
}
}
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
clicked => {
root.show_aura_power = false;
root.show_fade_cover = false;
}
}
if root.show_aura_power: Button {
x: root.width - self.width - 6px;
y: 6px;
text: "";
height: 36px;
clicked => {
root.show_aura_power = false;
root.show_fade_cover = false;
}
}
}

View File

@@ -16,20 +16,28 @@ component FanTab inherits Rectangle {
in-out property <[Node]> nodes;
VerticalLayout {
padding: 5px;
HorizontalLayout {
if root.tab_enabled: Graph {
nodes <=> root.nodes;
}
if !root.tab_enabled: Rectangle {
Text {
font-size: 24px;
font-size: 16px;
text: @tr("This fan is not avilable on this machine");
}
}
}
Rectangle {
background: Palette.border;
height: 1px;
}
HorizontalLayout {
alignment: LayoutAlignment.end;
spacing: 10px;
padding: 10px;
CheckBox {
text: @tr("Enabled");
checked <=> root.enabled;

View File

@@ -0,0 +1,64 @@
import { Palette, TabWidget, Button, CheckBox, ScrollView } from "std-widgets.slint";
import { Graph, Node } from "../widgets/graph.slint";
import { SystemToggle, SystemDropdown } from "../widgets/common.slint";
import { Profile, FanType, FanPageData } from "../types/fan_types.slint";
export global GPUPageData {
// GPU mode and device state
in-out property <int> gpu_mux_mode: 1; // 0 = Ultra/Discreet, 1 = Integrated/Optimus
in-out property <int> dgpu_disabled: 0; // 1 == dGPU disabled
in-out property <int> egpu_enabled: 0; // 1 == eGPU (XGMobile) enabled
in-out property <[string]> gpu_modes_choises: [@tr("Integrated"), @tr("Hybrid")];
in-out property <bool> gpu_mux_available: false;
callback cb_set_gpu_mode(int);
}
export component PageGPU inherits Rectangle {
clip: true;
ScrollView {
VerticalLayout {
padding: 12px;
spacing: 8px;
Rectangle {
background: Palette.alternate-background;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 36px;
Text {
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Internal/Discrete GPU");
}
}
HorizontalLayout {
padding-right: 10px;
padding-left: 10px;
alignment: LayoutAlignment.space-between;
Rectangle {
height: 32px;
Text {
font-size: 16px;
text: @tr("Note: Changes take effect after a reboot. The dropdown always shows the current mode.");
}
}
}
HorizontalLayout {
SystemDropdown {
text: @tr("GPU mode");
model <=> GPUPageData.gpu_modes_choises;
current_index <=> GPUPageData.gpu_mux_mode;
current_value: GPUPageData.gpu_modes_choises[GPUPageData.gpu_mux_mode];
selected => {
GPUPageData.cb_set_gpu_mode(GPUPageData.gpu_mux_mode)
}
}
}
}
}
}

View File

@@ -51,14 +51,6 @@ export global SystemPageData {
callback cb_panel_overdrive(int);
in-out property <int> boot_sound;
callback cb_boot_sound(int);
in-out property <int> kbd_leds_awake;
callback cb_kbd_leds_awake(int);
in-out property <int> kbd_leds_sleep;
callback cb_kbd_leds_sleep(int);
in-out property <int> kbd_leds_boot;
callback cb_kbd_leds_boot(int);
in-out property <int> kbd_leds_shutdown;
callback cb_kbd_leds_shutdown(int);
in-out property <int> screen_auto_brightness;
callback cb_screen_auto_brightness(int);
in-out property <int> mcu_powersave;
@@ -152,21 +144,20 @@ export component PageSystem inherits Rectangle {
property <bool> show_fade_cover: false;
property <bool> show_throttle_advanced: false;
clip: true;
//padding only has effect on layout elements
//padding: 8px;
ScrollView {
VerticalLayout {
padding: 10px;
spacing: 10px;
padding: 12px;
spacing: 8px;
alignment: LayoutAlignment.start;
Rectangle {
background: Palette.alternate-background;
border-color: Palette.accent-background;
border-width: 3px;
border-radius: 10px;
height: 40px;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 36px;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Power settings");
@@ -212,11 +203,11 @@ export component PageSystem inherits Rectangle {
padding-left: 10px;
padding-right: 20px;
HorizontalLayout {
width: 38%;
width: 40%;
alignment: LayoutAlignment.space-between;
padding-right: 15px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: @tr("Screenpad brightness");
@@ -240,7 +231,7 @@ export component PageSystem inherits Rectangle {
HorizontalLayout {
width: 20%;
padding-left: 10px;
padding-left: 14px;
alignment: LayoutAlignment.stretch;
Switch {
text: @tr("Sync with primary");
@@ -255,12 +246,12 @@ export component PageSystem inherits Rectangle {
Rectangle {
background: Palette.alternate-background;
border-color: Palette.accent-background;
border-width: 3px;
border-radius: 10px;
height: 40px;
border-color: Palette.border;
border-width: 1px;
border-radius: 2px;
height: 36px;
Text {
font-size: 18px;
font-size: 16px;
color: Palette.control-foreground;
horizontal-alignment: TextHorizontalAlignment.center;
text: @tr("Armoury settings");
@@ -268,62 +259,26 @@ export component PageSystem inherits Rectangle {
}
if !SystemPageData.asus_armoury_loaded: Rectangle {
border-width: 3px;
border-color: red;
background: maroon;
// background: darkred;
max-height: 30px;
VerticalBox {
Text {
text: @tr("no_asus_armoury_driver_1" => "The asus-armoury driver is not loaded");
font-size: 16px;
color: white;
horizontal-alignment: TextHorizontalAlignment.center;
}
Text {
text: @tr("no_asus_armoury_driver_2" => "For advanced features you will require a kernel with this driver added.");
font-size: 16px;
color: white;
horizontal-alignment: TextHorizontalAlignment.center;
}
}
}
GroupBox {
title: @tr("Keyboard Power Management");
HorizontalLayout {
spacing: 10px;
if SystemPageData.kbd_leds_awake != -1: SystemToggleInt {
text: @tr("Keyboard Awake Effect");
checked_int <=> SystemPageData.kbd_leds_awake;
toggled => {
SystemPageData.cb_kbd_leds_awake(SystemPageData.kbd_leds_awake)
}
}
if SystemPageData.kbd_leds_sleep != -1: SystemToggleInt {
text: @tr("Keyboard Sleep Effect");
checked_int <=> SystemPageData.kbd_leds_sleep;
toggled => {
SystemPageData.cb_kbd_leds_sleep(SystemPageData.kbd_leds_sleep)
}
}
if SystemPageData.kbd_leds_boot != -1: SystemToggleInt {
text: @tr("Keyboard Boot Effect");
checked_int <=> SystemPageData.kbd_leds_boot;
toggled => {
SystemPageData.cb_kbd_leds_boot(SystemPageData.kbd_leds_boot)
}
}
if SystemPageData.kbd_leds_shutdown != -1: SystemToggleInt {
text: @tr("Keyboard Shutdown Effect");
checked_int <=> SystemPageData.kbd_leds_shutdown;
toggled => {
SystemPageData.cb_kbd_leds_shutdown(SystemPageData.kbd_leds_shutdown)
}
}
}
}
HorizontalBox {
padding: 0px;
spacing: 10px;
@@ -561,20 +516,22 @@ export component PageSystem inherits Rectangle {
}
if root.show_throttle_advanced: Rectangle {
background: Palette.background;
width: 100%;
height: 100%;
opacity: 1;
ScrollView {
VerticalLayout {
padding: 50px;
padding-top: 5px;
padding-bottom: 100px;
alignment: start;
padding: 5px;
padding-top: 15px;
spacing: 10px;
GroupBox {
VerticalBox {
alignment: start;
spacing: 10px;
Text {
font-size: 18px;
font-size: 16px;
horizontal-alignment: TextHorizontalAlignment.center;
vertical-alignment: TextVerticalAlignment.center;
text: @tr("Energy Performance Preference linked to Throttle Policy");
@@ -609,7 +566,7 @@ export component PageSystem inherits Rectangle {
}
SystemDropdown {
text: @tr("EPP for Quiet Policy");
text: @tr("EPP for ") + SystemPageData.platform_profile_choices[2] + @tr(" Policy");
current_index <=> SystemPageData.profile_quiet_epp;
current_value: SystemPageData.energy_performance_choices[SystemPageData.profile_quiet_epp];
model <=> SystemPageData.energy_performance_choices;
@@ -622,9 +579,10 @@ export component PageSystem inherits Rectangle {
GroupBox {
VerticalBox {
alignment: start;
spacing: 10px;
Text {
font-size: 18px;
font-size: 16px;
horizontal-alignment: TextHorizontalAlignment.center;
vertical-alignment: TextVerticalAlignment.center;
text: @tr("Throttle Policy for power state");
@@ -679,8 +637,8 @@ export component PageSystem inherits Rectangle {
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "X";
height: 40px;
text: "";
height: 34px;
clicked => {
root.show_throttle_advanced = false;
root.show_fade_cover = false;

View File

@@ -46,8 +46,10 @@ export struct LaptopAuraPower {
states: [AuraPowerState],
}
// Modes with colour1: Static,Breathe,Star,Rain,Highlight,Laser,Ripple,Pulse,Comet,Flash (excl. Strobe,Rainbow,Nothing)
// Modes with colour2: Breathe, Star only.
// Speed: Breathe,Strobe,Rainbow,Star,Rain,Highlight,Laser,Ripple. Direction: Rainbow only.
export global AuraPageData {
// The ordering must match the rog-aura crate
in-out property <[string]> power_zone_names: [
@tr("Aura power zone" => "Logo"),
@tr("Aura power zone" => "Keyboard"),
@@ -87,15 +89,9 @@ export global AuraPageData {
@tr("Basic aura mode" => "Comet"),
@tr("Basic aura mode" => "Flash"),
];
in-out property <[string]> available_mode_names: [
@tr("Basic aura mode" => "Static"),
@tr("Basic aura mode" => "Breathe"),
@tr("Basic aura mode" => "Strobe"),
];
in-out property <[string]> available_mode_names: [ @tr("Basic aura mode" => "Static"), @tr("Basic aura mode" => "Breathe"), @tr("Basic aura mode" => "Strobe") ];
in-out property <int> current_available_mode: 0;
in-out property <[int]> supported_basic_modes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12];
in-out property <int> led_mode;
callback cb_led_mode(int);
in-out property <[string]> zone_names: [
@tr("Aura zone" => "None"),
@tr("Aura zone" => "Key1"),
@@ -106,51 +102,57 @@ export global AuraPageData {
@tr("Aura zone" => "Lightbar Left"),
@tr("Aura zone" => "Lightbar Right"),
];
in-out property <int> zone;
in-out property <[string]> direction_names: [
@tr("Aura direction" => "Right"),
@tr("Aura direction" => "Left"),
@tr("Aura direction" => "Up"),
@tr("Aura direction" => "Down"),
];
in-out property <int> direction;
in-out property <[string]> speed_names: [
@tr("Aura speed" => "Low"),
@tr("Aura speed" => "Medium"),
@tr("Aura speed" => "High"),
];
in-out property <int> speed;
in-out property <AuraEffect> led_mode_data: {
mode: 0,
zone: 0,
colour1: Colors.aquamarine,
colourbox1: Colors.aquamarine,
colour2: Colors.hotpink,
colourbox2: Colors.hotpink,
speed: 0,
direction: 0,
};
callback cb_led_mode_data(AuraEffect);
in-out property <color> color1;
in-out property <brush> colorbox1;
in-out property <color> color2;
in-out property <brush> colorbox2;
out property <bool> colour1_enabled: led_mode_data.mode == 0 || led_mode_data.mode == 1 || led_mode_data.mode == 4 || led_mode_data.mode == 6 || led_mode_data.mode == 7 || led_mode_data.mode == 8 || led_mode_data.mode == 10 || led_mode_data.mode == 11 || led_mode_data.mode == 12;
out property <bool> colour2_enabled: led_mode_data.mode == 1 || led_mode_data.mode == 4;
out property <bool> speed_enabled: led_mode_data.mode == 1 || led_mode_data.mode == 2 || led_mode_data.mode == 3 || led_mode_data.mode == 4 || led_mode_data.mode == 5 || led_mode_data.mode == 6 || led_mode_data.mode == 7 || led_mode_data.mode == 8;
out property <bool> direction_enabled: led_mode_data.mode == 3;
callback apply_led_mode_data();
callback apply_effect(AuraEffect);
apply_effect(e) => { led_mode_data = e; apply_led_mode_data(); }
in-out property <int> zone;
in-out property <int> speed;
in-out property <int> direction;
callback update_led_mode_data(AuraEffect);
update_led_mode_data(data) => {
led_mode_data = data;
current_available_mode = data.mode;
zone = data.zone;
speed = data.speed;
direction = data.direction;
color1 = data.colour1;
color2 = data.colour2;
colorbox1 = data.colour1;
colorbox2 = data.colour2;
update_led_mode_data(d) => {
led_mode_data = d;
zone = d.zone;
speed = d.speed;
direction = d.direction;
color1 = d.colour1;
color2 = d.colour2;
colorbox1 = d.colour1;
colorbox2 = d.colour2;
}
callback cb_hex_from_colour(color) -> string;
callback cb_hex_to_colour(string) -> color;
in-out property <AuraDevType> device_type: AuraDevType.Old;
// List of indexes to power_zone_names. Must correspond to rog-aura crate
in-out property <[PowerZones]> supported_power_zones: [
PowerZones.Keyboard,
PowerZones.Lightbar,

View File

@@ -4,8 +4,6 @@ import { PowerZones } from "../types/aura_types.slint";
export component AuraPowerGroup inherits Rectangle {
min-width: row.min-width;
border-radius: 20px;
background: Palette.alternate-background;
opacity: 0.9;
in-out property <string> group-title;
in-out property <bool> boot_checked;
@@ -16,6 +14,7 @@ export component AuraPowerGroup inherits Rectangle {
callback awake_toggled(bool);
callback sleep_toggled(bool);
callback shutdown_toggled(bool);
VerticalBox {
spacing: 10px;
Text {
@@ -28,7 +27,7 @@ export component AuraPowerGroup inherits Rectangle {
row := HorizontalBox {
alignment: LayoutAlignment.center;
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Boot");
checked <=> root.boot_checked;
@@ -38,7 +37,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Awake");
checked <=> root.awake_checked;
@@ -48,7 +47,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Sleep");
checked <=> root.sleep_checked;
@@ -58,7 +57,7 @@ export component AuraPowerGroup inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Shutdown");
checked <=> root.shutdown_checked;
@@ -72,8 +71,6 @@ export component AuraPowerGroup inherits Rectangle {
export component AuraPowerGroupOld inherits Rectangle {
min-width: row.min-width;
border-radius: 20px;
background: Palette.alternate-background;
opacity: 0.9;
in-out property <int> current_zone;
in-out property <[int]> zones;
@@ -86,6 +83,7 @@ export component AuraPowerGroupOld inherits Rectangle {
callback awake_toggled(bool);
callback sleep_toggled(bool);
callback selected_zone(int);
VerticalBox {
spacing: 10px;
Text {
@@ -109,7 +107,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Boot");
checked <=> root.boot_checked;
@@ -119,7 +117,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Awake");
checked <=> root.awake_checked;
@@ -129,7 +127,7 @@ export component AuraPowerGroupOld inherits Rectangle {
}
SystemToggleVert {
min-width: 96px;
min-width: 128px;
max-height: 42px;
text: @tr("Sleep");
checked <=> root.sleep_checked;

View File

@@ -1,7 +1,7 @@
import { Palette, Slider, HorizontalBox, Button, LineEdit } from "std-widgets.slint";
export component ColourSlider inherits VerticalLayout {
spacing: 10px;
spacing: 12px;
in-out property <bool> enabled;
property <string> hex: "#FF0000";
in-out property <float> c1value <=> c1.value;
@@ -102,9 +102,9 @@ export component ColourSlider inherits VerticalLayout {
hex = set_hex_from_colour(final_colour);
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 13 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_colours[0], base_colours[1], base_colours[2], base_colours[3], base_colours[4], base_colours[5], base_colours[6], base_colours[7], base_colours[8], base_colours[9], base_colours[10], base_colours[11], base_colours[12], base_colours[13], base_colours[14], base_colours[15], base_colours[16], base_colours[17], base_colours[18], base_colours[19], base_colours[20], base_colours[21], base_colours[22], base_colours[23], base_colours[24], base_colours[25], base_colours[26], base_colours[27], base_colours[28], base_colours[29], base_colours[30], base_colours[31], base_colours[32], base_colours[33], base_colours[34], base_colours[35]);
@@ -127,9 +127,9 @@ export component ColourSlider inherits VerticalLayout {
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 11 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_saturation[0], base_saturation[1], base_saturation[2], base_saturation[3], base_saturation[4], base_saturation[5], base_saturation[6], base_saturation[7], base_saturation[8], base_saturation[9], base_saturation[10]);
@@ -151,9 +151,9 @@ export component ColourSlider inherits VerticalLayout {
}
Rectangle {
height: 32px;
border-width: 2px;
border-radius: 7px;
height: 28px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
// 11 colours
background: !root.enabled ? Palette.alternate-background : @linear-gradient(90deg, base_value[0], base_value[1], base_value[2], base_value[3], base_value[4], base_value[5], base_value[6], base_value[7], base_value[8], base_value[9], base_value[10]);
@@ -191,8 +191,8 @@ export component ColourSlider inherits VerticalLayout {
Rectangle {
width: self.height;
border-width: 2px;
border-radius: 7px;
border-width: 1px;
border-radius: 3px;
border-color: Palette.border;
background <=> root.colourbox;
}

View File

@@ -1,12 +1,11 @@
import { Palette, VerticalBox , StandardButton, Button, HorizontalBox, ComboBox, Switch, Slider} from "std-widgets.slint";
export component RogItem inherits Rectangle {
background: Palette.control-background;
border-color: Palette.border;
border-width: 3px;
border-radius: 10px;
min-height: 48px;
max-height: 56px;
border-width: 1px;
border-radius: 2px;
min-height: 44px;
max-height: 44px;
}
export component SystemSlider inherits RogItem {
@@ -30,14 +29,14 @@ export component SystemSlider inherits RogItem {
HorizontalLayout {
spacing: 6px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
}
Text {
font-size: 16px;
font-size: 14px;
horizontal-alignment: TextHorizontalAlignment.right;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
@@ -47,7 +46,7 @@ export component SystemSlider inherits RogItem {
}
HorizontalBox {
padding-right: 20px;
padding-right: 10px;
slider := Slider {
enabled: root.enabled;
maximum: root.maximum;
@@ -162,7 +161,7 @@ export component SystemToggle inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -193,7 +192,7 @@ export component SystemToggleInt inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -223,7 +222,7 @@ export component SystemToggleVert inherits RogItem {
alignment: LayoutAlignment.space-around;
padding-top: 8px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.bottom;
horizontal-alignment: TextHorizontalAlignment.center;
color: Palette.control-foreground;
@@ -254,7 +253,7 @@ export component SystemDropdown inherits RogItem {
alignment: LayoutAlignment.start;
padding-left: 10px;
Text {
font-size: 16px;
font-size: 14px;
vertical-alignment: TextVerticalAlignment.center;
color: Palette.control-foreground;
text: root.text;
@@ -291,11 +290,7 @@ export component PopupNotification {
border-width: 2px;
border-color: Palette.accent-background;
background: Palette.background;
// TODO: drop shadows slow
// drop-shadow-offset-x: 7px;
// drop-shadow-offset-y: 7px;
// drop-shadow-color: black;
// drop-shadow-blur: 30px;
VerticalLayout {
Dialog {
VerticalLayout {

View File

@@ -191,10 +191,11 @@ export component Graph inherits Rectangle {
tip := Rectangle {
background: Palette.control-foreground;
opacity: 0.3;
border-radius: 12px;
x: final_x_pos();
y: final_y_pos();
width: label.preferred-width;
height: label.preferred-height;
width: label.preferred-width + 14px;
height: label.preferred-height + 4px;
function x_pos() -> length {
scale_x_to_graph(n.x) - label.preferred-width - 8px
}
@@ -225,7 +226,7 @@ export component Graph inherits Rectangle {
//
label := Text {
color: Palette.accent-foreground;
font-size: 16px;
font-size: 14px;
text: "\{Math.floor(n.x / 1px)}c, \{fan_pct()}%";
}
}

View File

@@ -4,8 +4,6 @@
import { Palette, HorizontalBox, VerticalBox } from "std-widgets.slint";
component SideBarItem inherits Rectangle {
// padding only has effect on layout elements
// padding: 10px;
in property <bool> selected;
in property <bool> has-focus;
in-out property <string> text <=> label.text;
@@ -26,18 +24,16 @@ component SideBarItem inherits Rectangle {
state.opacity: 0.8;
}
]
state := Rectangle {
opacity: 0;
border-width: 2px;
border-radius: 10px;
border-color: Palette.accent-background;
background: Palette.alternate-background;
background: Palette.selection-background;
animate opacity { duration: 150ms; }
animate border-width { duration: 150ms; }
height: l.preferred-height;
}
l := HorizontalBox {
x: 4px;
y: (parent.height - self.height) / 2;
spacing: 0px;
label := Text {
@@ -56,20 +52,17 @@ component SideBarItem inherits Rectangle {
export component SideBar inherits Rectangle {
in property <[string]> model: [];
in property <[bool]> available: [];
in property <string> title <=> label.text;
in property <bool> is_tuf: false;
out property <int> current-item: 0;
out property <int> current-focused: fs.has-focus ? fs.focused-tab : -1;
// The currently focused tab
width: 160px;
width: 180px;
forward-focus: fs;
accessible-role: tab;
accessible-delegate-focus: root.current-focused >= 0 ? root.current-focused : root.current-item;
Rectangle {
border-width: 2px;
border-color: Palette.accent-background;
border-radius: 0px;
background: Palette.background.darker(0.2);
background: Palette.alternate-background;
fs := FocusScope {
key-pressed(event) => {
if (event.text == "\n") {
@@ -102,10 +95,22 @@ export component SideBar inherits Rectangle {
VerticalBox {
spacing: 4px;
padding: 0px;
alignment: start;
label := Text {
font-size: 16px;
Image {
height: 100px;
// TODO: change if TUF on the logo in the menu on the main page
// If running on a TUF model, replace the ROG red with TUF orange
// (add data/tuf-control-center.png and switch here when available)
source: @image-url("../../data/rog-control-center.png");
horizontal-alignment: center;
image-fit: contain;
}
Rectangle {
height: 1px;
background: Palette.border;
}
navigation := VerticalLayout {

View File

@@ -5,7 +5,7 @@ use zbus::proxy;
#[proxy(
interface = "xyz.ljones.Anime",
default_service = "xyz.ljones.Asusd",
default_path = "/xyz/ljones"
default_path = "/xyz/ljones/aura/anime"
)]
pub trait Anime {
/// DeviceState method

View File

@@ -253,8 +253,18 @@ impl FirmwareAttributes {
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum FirmwareAttributeType {
#[default]
Immediate,
Ppt,
Gpu,
Bios,
}
macro_rules! define_attribute_getters {
($($attr:ident),*) => {
// Accept a list of attribute idents and an optional `types { .. }` block
( $( $attr:ident ),* $(,)? $( ; types { $( $tattr:ident : $ptype:ident ),* $(,)? } )? ) => {
impl FirmwareAttributes {
$(
pub fn $attr(&self) -> Option<&Attribute> {
@@ -268,6 +278,17 @@ macro_rules! define_attribute_getters {
});
)*
}
impl FirmwareAttribute {
pub fn property_type(&self) -> FirmwareAttributeType {
match <&str>::from(*self) {
$(
$( stringify!($tattr) => FirmwareAttributeType::$ptype, )*
)?
_ => FirmwareAttributeType::Immediate,
}
}
}
}
}
@@ -299,6 +320,33 @@ define_attribute_getters!(
gpu_mux_mode,
mini_led_mode,
screen_auto_brightness
; types {
ppt_pl1_spl: Ppt,
ppt_pl2_sppt: Ppt,
ppt_apu_sppt: Ppt,
ppt_platform_sppt: Ppt,
ppt_fppt: Ppt,
nv_dynamic_boost: Ppt,
nv_temp_target: Ppt,
dgpu_base_tgp: Ppt,
dgpu_tgp: Ppt,
gpu_mux_mode: Gpu,
egpu_connected: Gpu,
egpu_enable: Gpu,
dgpu_disable: Gpu,
boot_sound: Bios,
mcu_powersave: Immediate,
screen_auto_brightness: Immediate,
mini_led_mode: Immediate,
panel_hd_mode: Immediate,
panel_od: Immediate,
charge_mode: Immediate,
}
);
/// CamelCase names of the properties. Intended for use with DBUS
@@ -346,33 +394,6 @@ pub enum FirmwareAttribute {
PptEnabled = 24,
None = 25,
ScreenAutoBrightness = 26,
KbdLedsAwake = 27,
KbdLedsSleep = 28,
KbdLedsBoot = 29,
KbdLedsShutdown = 30,
}
impl FirmwareAttribute {
pub fn is_ppt(&self) -> bool {
matches!(
self,
FirmwareAttribute::PptPl1Spl
| FirmwareAttribute::PptPl2Sppt
| FirmwareAttribute::PptPl3Fppt
| FirmwareAttribute::PptFppt
| FirmwareAttribute::PptApuSppt
| FirmwareAttribute::PptPlatformSppt
)
}
pub fn is_dgpu(&self) -> bool {
matches!(
self,
FirmwareAttribute::NvDynamicBoost
| FirmwareAttribute::NvTempTarget
| FirmwareAttribute::DgpuTgp
)
}
}
impl From<&str> for FirmwareAttribute {
@@ -394,10 +415,6 @@ impl From<&str> for FirmwareAttribute {
"nv_tgp" => Self::DgpuTgp,
"charge_mode" => Self::ChargeMode,
"boot_sound" => Self::BootSound,
"kbd_leds_awake" => Self::KbdLedsAwake,
"kbd_leds_sleep" => Self::KbdLedsSleep,
"kbd_leds_boot" => Self::KbdLedsBoot,
"kbd_leds_shutdown" => Self::KbdLedsShutdown,
"mcu_powersave" => Self::McuPowersave,
"panel_overdrive" => Self::PanelOverdrive,
"panel_hd_mode" => Self::PanelHdMode,
@@ -443,10 +460,6 @@ impl From<FirmwareAttribute> for &str {
FirmwareAttribute::DgpuDisable => "dgpu_disable",
FirmwareAttribute::GpuMuxMode => "gpu_mux_mode",
FirmwareAttribute::MiniLedMode => "mini_led_mode",
FirmwareAttribute::KbdLedsAwake => "kbd_leds_awake",
FirmwareAttribute::KbdLedsSleep => "kbd_leds_sleep",
FirmwareAttribute::KbdLedsBoot => "kbd_leds_boot",
FirmwareAttribute::KbdLedsShutdown => "kbd_leds_shutdown",
FirmwareAttribute::PendingReboot => "pending_reboot",
FirmwareAttribute::ScreenAutoBrightness => "screen_auto_brightness",
FirmwareAttribute::None => "none",

View File

@@ -0,0 +1,70 @@
use super::Row;
// TODO: This is a placeholder for G635L map
pub const G635L: [Row; 63] = [
Row(0x01, 7, 32, 0),
Row(0x01, 7 + 34, 32, 0),
Row(0x01, 7 + 68, 32, 0),
Row(0x01, 7 + 102, 32, 0), // 34 len
Row(0x01, 7 + 136, 32, 0),
Row(0x01, 7 + 170, 34, 0),
Row(0x01, 7 + 204, 34, 0),
Row(0x01, 7 + 238, 34, 0),
Row(0x01, 7 + 272, 34, 0),
Row(0x01, 7 + 306, 34, 0),
Row(0x01, 7 + 340, 34, 0),
Row(0x01, 7 + 374, 34, 0),
Row(0x01, 7 + 408, 33, 1),
Row(0x01, 7 + 441, 33, 1),
Row(0x01, 7 + 474, 32, 2),
Row(0x01, 7 + 506, 32, 2),
Row(0x01, 7 + 538, 31, 3),
Row(0x01, 7 + 569, 31, 3),
Row(0x01, 7 + 600, 28, 4),
//
Row(0x74, 7 + 1, 3, 28 + 4), // adds to end of previous
Row(0x74, 7 + 3, 30, 4),
Row(0x74, 7 + 33, 29, 5),
Row(0x74, 7 + 62, 29, 5),
Row(0x74, 7 + 91, 28, 6),
Row(0x74, 7 + 119, 28, 6),
Row(0x74, 7 + 147, 27, 7),
Row(0x74, 7 + 174, 27, 7),
Row(0x74, 7 + 202, 26, 9),
Row(0x74, 7 + 228, 26, 9),
Row(0x74, 7 + 254, 25, 10),
Row(0x74, 7 + 278, 25, 9), // WEIRD OFFSET
Row(0x74, 7 + 303, 24, 10),
Row(0x74, 7 + 327, 24, 10),
Row(0x74, 7 + 351, 23, 11),
Row(0x74, 7 + 374, 23, 11),
Row(0x74, 7 + 397, 22, 12),
Row(0x74, 7 + 419, 22, 12),
Row(0x74, 7 + 441, 21, 13),
Row(0x74, 7 + 462, 21, 13),
Row(0x74, 7 + 483, 20, 14),
Row(0x74, 7 + 503, 20, 14),
Row(0x74, 7 + 523, 19, 15),
Row(0x74, 7 + 542, 19, 15),
Row(0x74, 7 + 561, 18, 16),
Row(0x74, 7 + 579, 18, 16),
Row(0x74, 7 + 597, 17, 17),
Row(0x74, 7 + 614, 13, 17),
//
Row(0xe7, 7 + 1, 4, 13 + 18), // adds to end of previous
Row(0xe7, 7 + 4, 16, 18),
Row(0xe7, 7 + 20, 16, 18),
Row(0xe7, 7 + 36, 15, 19),
Row(0xe7, 7 + 51, 15, 19),
Row(0xe7, 7 + 66, 14, 20),
Row(0xe7, 7 + 80, 12, 20), // too long? 14
Row(0xe7, 7 + 94, 13, 21),
Row(0xe7, 7 + 107, 13, 21),
Row(0xe7, 7 + 120, 12, 12), // Actual display end
Row(0xe7, 7 + 132, 12, 22),
Row(0xe7, 7 + 144, 11, 23),
Row(0xe7, 7 + 155, 11, 23),
Row(0xe7, 7 + 166, 10, 24),
Row(0xe7, 7 + 176, 10, 24),
Row(0xe7, 7 + 186, 9, 25),
];

View File

@@ -0,0 +1,74 @@
use super::Row;
// G835L layout: 68 rows (triangle + rectangle), 2 packets
pub const G835L: [Row; 69] = [
Row(0x01, 7, 0, 0),
Row(0x01, 8, 0, 0),
Row(0x01, 9, 1, 0),
Row(0x01, 11, 1, 0),
Row(0x01, 13, 2, 0),
Row(0x01, 16, 2, 0),
Row(0x01, 19, 3, 0),
Row(0x01, 23, 3, 0),
Row(0x01, 27, 4, 0),
Row(0x01, 32, 4, 0),
Row(0x01, 37, 5, 0),
Row(0x01, 43, 5, 0),
Row(0x01, 49, 6, 0),
Row(0x01, 56, 6, 0),
Row(0x01, 63, 7, 0),
Row(0x01, 71, 7, 0),
Row(0x01, 79, 8, 0),
Row(0x01, 88, 8, 0),
Row(0x01, 97, 9, 0),
Row(0x01, 107, 9, 0),
Row(0x01, 117, 10, 0),
Row(0x01, 128, 10, 0),
Row(0x01, 139, 11, 0),
Row(0x01, 151, 11, 0),
Row(0x01, 163, 12, 0),
Row(0x01, 176, 12, 0),
Row(0x01, 189, 13, 0),
Row(0x01, 203, 13, 0),
Row(0x01, 217, 14, 0),
Row(0x01, 232, 14, 0),
Row(0x01, 247, 14, 1),
Row(0x01, 262, 14, 1),
Row(0x01, 277, 14, 2),
Row(0x01, 292, 14, 2),
Row(0x01, 307, 14, 3),
Row(0x01, 322, 14, 3),
Row(0x01, 337, 14, 4),
Row(0x01, 352, 14, 4),
Row(0x01, 367, 14, 5),
Row(0x01, 382, 14, 5),
Row(0x01, 397, 14, 6),
Row(0x01, 412, 14, 6),
Row(0x01, 427, 14, 7),
Row(0x01, 442, 14, 7),
Row(0x01, 457, 14, 8),
Row(0x01, 472, 14, 8),
Row(0x01, 487, 14, 9),
Row(0x01, 502, 14, 9),
Row(0x01, 517, 14, 10),
Row(0x01, 532, 14, 10),
Row(0x01, 547, 14, 11),
Row(0x01, 562, 14, 11),
Row(0x01, 577, 14, 12),
Row(0x01, 592, 14, 12),
Row(0x01, 607, 14, 13),
Row(0x01, 622, 11, 13),
Row(0x74, 7, 2, 25),
Row(0x74, 10, 14, 14),
Row(0x74, 25, 14, 14),
Row(0x74, 40, 14, 15),
Row(0x74, 55, 14, 15),
Row(0x74, 70, 14, 16),
Row(0x74, 85, 14, 16),
Row(0x74, 100, 14, 17),
Row(0x74, 115, 14, 17),
Row(0x74, 130, 14, 18),
Row(0x74, 145, 14, 18),
Row(0x74, 160, 14, 19),
Row(0x74, 175, 14, 19),
];

View File

@@ -1,9 +1,13 @@
use rog_anime::AnimeType;
use self::map_g635l::G635L;
use self::map_g835l::G835L;
use self::map_ga401::GA401;
use self::map_ga402::GA402;
use self::map_gu604::GU604;
mod map_g635l;
mod map_g835l;
mod map_ga401;
mod map_ga402;
mod map_gu604;
@@ -38,30 +42,18 @@ pub struct AniMatrix {
impl AniMatrix {
pub fn new(model: AnimeType) -> Self {
let led_shape = match model {
AnimeType::GA401 => LedShape {
vertical: 2,
horizontal: 5,
},
AnimeType::GA402 | AnimeType::G635L | AnimeType::G835L | AnimeType::Unsupported => {
LedShape {
vertical: 2,
horizontal: 5,
}
}
AnimeType::GU604 => LedShape {
vertical: 2,
horizontal: 5,
},
let led_shape = LedShape {
vertical: 2,
horizontal: 5,
};
// Do a hard mapping of each (derived from wireshardk captures)
let rows = match model {
AnimeType::GA401 => GA401.to_vec(),
AnimeType::GA402 | AnimeType::G635L | AnimeType::G835L | AnimeType::Unsupported => {
GA402.to_vec()
}
AnimeType::GA402 | AnimeType::Unsupported => GA402.to_vec(),
AnimeType::GU604 => GU604.to_vec(),
AnimeType::G635L => G635L.to_vec(),
AnimeType::G835L => G835L.to_vec(),
};
Self { rows, led_shape }

View File

@@ -2,7 +2,6 @@ use std::env;
use std::error::Error;
use std::str::FromStr;
use log::error;
use rog_anime::usb::{PROD_ID, VENDOR_ID};
use rog_anime::{AnimeType, USB_PREFIX2};
use sdl2::event::Event;
@@ -20,6 +19,7 @@ pub struct VirtAnimeMatrix {
animatrix: AniMatrix,
}
// TODO: This isn't working
impl VirtAnimeMatrix {
pub fn new(model: AnimeType) -> Self {
VirtAnimeMatrix {
@@ -86,8 +86,12 @@ impl VirtAnimeMatrix {
]
.to_vec(),
})
.map_err(|err| error!("Could not create virtual device: {:?}", err))
.expect("Could not create virtual device"),
.unwrap_or_else(|err| {
panic!(
"Could not create virtual device: {err:?}. \
Try loading the uhid module and ensure you have the necessary permissions."
)
}),
}
}
@@ -114,7 +118,7 @@ impl VirtAnimeMatrix {
fn main() -> Result<(), Box<dyn Error>> {
let args: Vec<String> = env::args().collect();
if args.len() <= 1 {
println!("Must supply arg, one of <GA401, GA402, GU604>");
println!("Must supply arg, one of <GA401, GA402, GU604, G835L>");
return Ok(());
}
let anime_type = AnimeType::from_str(&args[1])?;