Compare commits

..

25 Commits

Author SHA1 Message Date
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
42 changed files with 2495 additions and 593 deletions

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

@@ -5,6 +5,10 @@
### 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]

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(());
}

View File

@@ -211,17 +211,24 @@ impl crate::Reloadable for AsusArmouryAttribute {
}
};
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set {} value: {e:?}", self.attr.name());
self.attr.base_path_exists();
e
})?;
match apply_value {
AttrValue::None => {
info!(
"No saved value for attribute {}: skipping.",
self.attr.name()
);
}
_ => {
info!("Applying value {apply_value:?} to attribute {name}");
self.attr.set_current_value(&apply_value).map_err(|e| {
error!("Could not set {name} value: {e:?}");
self.attr.base_path_exists();
e
})?;
info!(
"Restored asus-armoury setting {} to {:?}",
self.attr.name(),
apply_value
);
info!("Restored asus-armoury setting {name} to {apply_value:?}");
}
}
Ok(())
}

View File

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

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

@@ -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) => {
@@ -59,10 +77,12 @@ export component MainWindow inherits Window {
@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;
}
Button {
@@ -82,26 +102,40 @@ 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 {

View File

@@ -42,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,
});
}
}
}
@@ -62,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,
});
}
}
}
@@ -116,63 +117,63 @@ export component PageAura inherits Rectangle {
max-height: 90px;
RogItem {
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 {
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 {
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,
});
}
}
}
@@ -237,15 +238,47 @@ export component PageAura inherits Rectangle {
}
}
}
}
}
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "✕";
height: 36px;
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);
}
}
}
}
@@ -291,17 +324,17 @@ export component PageAura inherits Rectangle {
}
}
}
}
}
Button {
x: root.width - self.width - 6px;
y: 6px;
text: "✕";
height: 36px;
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

@@ -0,0 +1,80 @@
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("Coming Soon: GPU Configuration");
}
}
/*
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;
@@ -287,44 +279,6 @@ export component PageSystem inherits Rectangle {
}
}
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;
@@ -612,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;

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

@@ -52,6 +52,7 @@ component SideBarItem inherits Rectangle {
export component SideBar inherits Rectangle {
in property <[string]> model: [];
in property <[bool]> available: [];
in property <bool> is_tuf: false;
out property <int> current-item: 0;
out property <int> current-focused: fs.has-focus ? fs.focused-tab : -1;
@@ -99,6 +100,9 @@ export component SideBar inherits Rectangle {
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;

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

@@ -257,7 +257,6 @@ impl FirmwareAttributes {
pub enum FirmwareAttributeType {
#[default]
Immediate,
TUFKeyboard,
Ppt,
Gpu,
Bios,
@@ -346,11 +345,6 @@ define_attribute_getters!(
panel_hd_mode: Immediate,
panel_od: Immediate,
kbd_leds_awake: TUFKeyboard,
kbd_leds_sleep: TUFKeyboard,
kbd_leds_boot: TUFKeyboard,
kbd_leds_shutdown: TUFKeyboard,
charge_mode: Immediate,
}
);
@@ -400,10 +394,6 @@ pub enum FirmwareAttribute {
PptEnabled = 24,
None = 25,
ScreenAutoBrightness = 26,
KbdLedsAwake = 27,
KbdLedsSleep = 28,
KbdLedsBoot = 29,
KbdLedsShutdown = 30,
}
impl From<&str> for FirmwareAttribute {
@@ -425,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,
@@ -474,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])?;