mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 09:23:19 +01:00
SCSI support: ROG Arion external drive LED control
This commit is contained in:
@@ -2,10 +2,13 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- ROG Arion external driver LED support
|
||||
- Add GA605W LED layout
|
||||
|
||||
### Changed
|
||||
- Fix attribute writes. At some point the kernel API seems to have changed.
|
||||
- Extremely large refactor of Aura device handling. Should enable easy add of different kinds now.
|
||||
- Add GA605W LED layout
|
||||
- Rename CLI args for aura related properties. This will likely change further as more devices are added
|
||||
|
||||
## [v6.0.12]
|
||||
|
||||
149
Cargo.lock
generated
149
Cargo.lock
generated
@@ -187,6 +187,7 @@ dependencies = [
|
||||
"rog_dbus",
|
||||
"rog_platform",
|
||||
"rog_profiles",
|
||||
"rog_scsi",
|
||||
"rog_slash",
|
||||
"ron",
|
||||
"zbus 5.2.0",
|
||||
@@ -210,6 +211,7 @@ dependencies = [
|
||||
"rog_aura",
|
||||
"rog_platform",
|
||||
"rog_profiles",
|
||||
"rog_scsi",
|
||||
"rog_slash",
|
||||
"serde",
|
||||
"tokio",
|
||||
@@ -549,12 +551,32 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"shlex",
|
||||
"syn 2.0.90",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.71.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f58bf3d7db68cfbac37cfc485a8d711e87e064c3d0fe0435b92f7a407f9d6b3"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash 2.1.0",
|
||||
"shlex",
|
||||
"syn 2.0.90",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit_field"
|
||||
version = "0.10.2"
|
||||
@@ -648,18 +670,18 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.20.0"
|
||||
version = "1.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a"
|
||||
checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3"
|
||||
dependencies = [
|
||||
"bytemuck_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck_derive"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec"
|
||||
checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -731,9 +753,9 @@ checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.4"
|
||||
version = "1.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
|
||||
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
@@ -930,7 +952,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "const-field-offset"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"const-field-offset-macro",
|
||||
"field-offset",
|
||||
@@ -939,7 +961,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "const-field-offset-macro"
|
||||
version = "0.1.5"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2150,8 +2172,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-backend-linuxkms"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"calloop 0.14.2",
|
||||
"drm",
|
||||
@@ -2168,8 +2190,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-backend-selector"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"i-slint-backend-linuxkms",
|
||||
@@ -2181,8 +2203,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-backend-winit"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"ashpd",
|
||||
"cfg-if",
|
||||
@@ -2212,8 +2234,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-common"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"derive_more",
|
||||
@@ -2224,8 +2246,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-compiler"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"by_address",
|
||||
"codemap",
|
||||
@@ -2254,8 +2276,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-core"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"auto_enums",
|
||||
"bitflags 2.6.0",
|
||||
@@ -2299,8 +2321,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-core-macros"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"serde_json",
|
||||
@@ -2309,8 +2331,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-renderer-femtovg"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"const-field-offset",
|
||||
@@ -2339,8 +2361,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "i-slint-renderer-skia"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
"cfg-if",
|
||||
@@ -3195,6 +3217,7 @@ dependencies = [
|
||||
"cfg_aliases",
|
||||
"libc",
|
||||
"memoffset",
|
||||
"pin-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3538,9 +3561,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
version = "0.36.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e"
|
||||
checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -3670,9 +3693,9 @@ checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.15"
|
||||
version = "0.17.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d"
|
||||
checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
@@ -4145,6 +4168,7 @@ dependencies = [
|
||||
"rog_aura",
|
||||
"rog_platform",
|
||||
"rog_profiles",
|
||||
"rog_scsi",
|
||||
"rog_slash",
|
||||
"zbus 5.2.0",
|
||||
]
|
||||
@@ -4177,6 +4201,19 @@ dependencies = [
|
||||
"zbus 5.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rog_scsi"
|
||||
version = "6.0.12"
|
||||
dependencies = [
|
||||
"cargo-husky",
|
||||
"log",
|
||||
"ron",
|
||||
"serde",
|
||||
"sg",
|
||||
"typeshare",
|
||||
"zbus 5.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rog_simulators"
|
||||
version = "6.0.12"
|
||||
@@ -4218,7 +4255,7 @@ checksum = "0a542b0253fa46e632d27a1dc5cf7b930de4df8659dc6e720b647fc72147ae3d"
|
||||
dependencies = [
|
||||
"countme",
|
||||
"hashbrown 0.14.5",
|
||||
"rustc-hash",
|
||||
"rustc-hash 1.1.0",
|
||||
"text-size",
|
||||
]
|
||||
|
||||
@@ -4250,6 +4287,12 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.4.1"
|
||||
@@ -4411,9 +4454,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.133"
|
||||
version = "1.0.134"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
|
||||
checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -4441,6 +4484,16 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sg"
|
||||
version = "0.4.0"
|
||||
source = "git+https://github.com/flukejones/sg-rs.git#b1ce961ae42b0aad22166bac84e5105a918debd3"
|
||||
dependencies = [
|
||||
"bindgen 0.71.1",
|
||||
"libc",
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@@ -4512,7 +4565,7 @@ version = "0.78.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29880a81b088de322e9c5306236c70761a61b5fa4df3c15c93bad3ce890ce34c"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bindgen 0.69.5",
|
||||
"cc",
|
||||
"flate2",
|
||||
"heck",
|
||||
@@ -4546,8 +4599,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "slint"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"const-field-offset",
|
||||
"i-slint-backend-selector",
|
||||
@@ -4563,8 +4616,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "slint-build"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"i-slint-compiler",
|
||||
"i-slint-core-macros",
|
||||
@@ -4575,8 +4628,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "slint-macros"
|
||||
version = "1.9.0"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
version = "1.9.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"i-slint-compiler",
|
||||
"proc-macro2",
|
||||
@@ -5023,9 +5076,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.8.0"
|
||||
version = "1.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938"
|
||||
checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
@@ -5357,7 +5410,7 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e24880fbcee511571ed9104b9a5273d1563d11ccaaf54b7c05cc6c100b652f9f"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"bindgen 0.69.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5537,7 +5590,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vtable"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"const-field-offset",
|
||||
"portable-atomic",
|
||||
@@ -5548,7 +5601,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "vtable-macro"
|
||||
version = "0.2.1"
|
||||
source = "git+https://github.com/slint-ui/slint.git#09c9857082ff0e5cef6cdb4ed4396aab9eafb9d4"
|
||||
source = "git+https://github.com/slint-ui/slint.git#e125da180d34df9e221cb925ea5c1af6e813bd8f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -6176,9 +6229,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winit"
|
||||
version = "0.30.5"
|
||||
version = "0.30.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0be9e76a1f1077e04a411f0b989cbd3c93339e1771cb41e71ac4aee95bfd2c67"
|
||||
checksum = "7c3d72dfa0f47e429290cd0d236884ca02f22dbd5dd33a43ad2b8bf4d79b6c18"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"android-activity",
|
||||
|
||||
@@ -25,7 +25,7 @@ members = [
|
||||
"rog-profiles",
|
||||
"rog-control-center",
|
||||
"rog-slash",
|
||||
"simulators",
|
||||
"simulators", "rog-scsi",
|
||||
]
|
||||
default-members = [
|
||||
"asusctl",
|
||||
@@ -73,6 +73,8 @@ versions = "6.2"
|
||||
|
||||
notify-rust = { version = "4.11.0", features = ["z", "async"] }
|
||||
|
||||
sg = {git = "https://github.com/flukejones/sg-rs.git"}
|
||||
|
||||
[profile.release]
|
||||
# thin = 57s, asusd = 9.0M
|
||||
# fat = 72s, asusd = 6.4M
|
||||
|
||||
@@ -10,6 +10,7 @@ edition.workspace = true
|
||||
|
||||
[dependencies]
|
||||
rog_anime = { path = "../rog-anime" }
|
||||
rog_scsi = { path = "../rog-scsi" }
|
||||
rog_slash = { path = "../rog-slash" }
|
||||
rog_aura = { path = "../rog-aura" }
|
||||
rog_dbus = { path = "../rog-dbus" }
|
||||
|
||||
@@ -4,6 +4,7 @@ use rog_platform::platform::ThrottlePolicy;
|
||||
use crate::anime_cli::AnimeCommand;
|
||||
use crate::aura_cli::{LedBrightness, LedPowerCommand1, LedPowerCommand2, SetAuraBuiltin};
|
||||
use crate::fan_curve_cli::FanCurveCommand;
|
||||
use crate::scsi_cli::ScsiCommand;
|
||||
use crate::slash_cli::SlashCommand;
|
||||
|
||||
#[derive(Default, Options)]
|
||||
@@ -46,6 +47,8 @@ pub enum CliCommand {
|
||||
Anime(AnimeCommand),
|
||||
#[options(name = "slash", help = "Manage Slash Ledbar")]
|
||||
Slash(SlashCommand),
|
||||
#[options(name = "scsi", help = "Manage SCSI external drive")]
|
||||
Scsi(ScsiCommand),
|
||||
#[options(help = "Change bios settings")]
|
||||
Platform(PlatformCommand),
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage,
|
||||
use rog_aura::keyboard::{AuraPowerState, LaptopAuraPower};
|
||||
use rog_aura::{self, AuraDeviceType, AuraEffect, PowerZones};
|
||||
use rog_dbus::list_iface_blocking;
|
||||
use rog_dbus::scsi_aura::ScsiAuraProxyBlocking;
|
||||
use rog_dbus::zbus_anime::AnimeProxyBlocking;
|
||||
use rog_dbus::zbus_aura::AuraProxyBlocking;
|
||||
use rog_dbus::zbus_fan_curves::FanCurvesProxyBlocking;
|
||||
@@ -21,8 +22,10 @@ use rog_dbus::zbus_platform::PlatformProxyBlocking;
|
||||
use rog_dbus::zbus_slash::SlashProxyBlocking;
|
||||
use rog_platform::platform::{GpuMode, Properties, ThrottlePolicy};
|
||||
use rog_profiles::error::ProfileError;
|
||||
use rog_scsi::AuraMode;
|
||||
use rog_slash::SlashMode;
|
||||
use ron::ser::PrettyConfig;
|
||||
use scsi_cli::ScsiCommand;
|
||||
use zbus::blocking::proxy::ProxyImpl;
|
||||
use zbus::blocking::Connection;
|
||||
|
||||
@@ -34,6 +37,7 @@ mod anime_cli;
|
||||
mod aura_cli;
|
||||
mod cli_opts;
|
||||
mod fan_curve_cli;
|
||||
mod scsi_cli;
|
||||
mod slash_cli;
|
||||
|
||||
fn main() {
|
||||
@@ -180,6 +184,7 @@ fn do_parsed(
|
||||
Some(CliCommand::Graphics(_)) => do_gfx(),
|
||||
Some(CliCommand::Anime(cmd)) => handle_anime(cmd)?,
|
||||
Some(CliCommand::Slash(cmd)) => handle_slash(cmd)?,
|
||||
Some(CliCommand::Scsi(cmd)) => handle_scsi(cmd)?,
|
||||
Some(CliCommand::Platform(cmd)) => {
|
||||
handle_platform_properties(&conn, supported_properties, cmd)?
|
||||
}
|
||||
@@ -579,6 +584,79 @@ fn handle_slash(cmd: &SlashCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_scsi(cmd: &ScsiCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if (!cmd.list && cmd.enable.is_none() && cmd.mode.is_none() && cmd.colours.is_empty())
|
||||
|| cmd.help
|
||||
{
|
||||
println!("Missing arg or command\n\n{}", cmd.self_usage());
|
||||
if let Some(lst) = cmd.self_command_list() {
|
||||
println!("\n{}", lst);
|
||||
}
|
||||
}
|
||||
|
||||
let scsis = find_iface::<ScsiAuraProxyBlocking>("org.asuslinux.ScsiAura")?;
|
||||
|
||||
for scsi in scsis {
|
||||
if let Some(enable) = cmd.enable {
|
||||
scsi.set_enabled(enable)?;
|
||||
}
|
||||
|
||||
if let Some(mode) = cmd.mode {
|
||||
dbg!(mode as u8);
|
||||
scsi.set_led_mode(mode).unwrap();
|
||||
}
|
||||
|
||||
let mut mode = scsi.led_mode_data()?;
|
||||
let mut do_update = false;
|
||||
if !cmd.colours.is_empty() {
|
||||
let mut count = 0;
|
||||
for c in &cmd.colours {
|
||||
if count == 0 {
|
||||
mode.colour1 = *c;
|
||||
}
|
||||
if count == 1 {
|
||||
mode.colour2 = *c;
|
||||
}
|
||||
if count == 2 {
|
||||
mode.colour3 = *c;
|
||||
}
|
||||
if count == 3 {
|
||||
mode.colour4 = *c;
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
if let Some(speed) = cmd.speed {
|
||||
mode.speed = speed;
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
if let Some(dir) = cmd.direction {
|
||||
mode.direction = dir;
|
||||
do_update = true;
|
||||
}
|
||||
|
||||
if do_update {
|
||||
scsi.set_led_mode_data(mode.clone())?;
|
||||
}
|
||||
|
||||
// let mode_ret = scsi.led_mode_data()?;
|
||||
// assert_eq!(mode, mode_ret);
|
||||
println!("{mode}");
|
||||
}
|
||||
|
||||
if cmd.list {
|
||||
let res = AuraMode::list();
|
||||
for p in &res {
|
||||
println!("{:?}", p);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_led_mode(mode: &LedModeCommand) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if mode.command.is_none() && !mode.prev_mode && !mode.next_mode {
|
||||
if !mode.help {
|
||||
|
||||
35
asusctl/src/scsi_cli.rs
Normal file
35
asusctl/src/scsi_cli.rs
Normal file
@@ -0,0 +1,35 @@
|
||||
use gumdrop::Options;
|
||||
use rog_scsi::{AuraMode, Colour, Direction, Speed};
|
||||
|
||||
#[derive(Options)]
|
||||
pub struct ScsiCommand {
|
||||
#[options(help = "print help message")]
|
||||
pub help: bool,
|
||||
|
||||
#[options(help = "Enable the SCSI drive LEDs")]
|
||||
pub enable: Option<bool>,
|
||||
|
||||
#[options(meta = "", help = "Set LED mode (so 'list' for all options)")]
|
||||
pub mode: Option<AuraMode>,
|
||||
|
||||
#[options(
|
||||
meta = "",
|
||||
help = "Set LED mode speed <slowest, slow, med, fast, fastest> (does not apply to all)"
|
||||
)]
|
||||
pub speed: Option<Speed>,
|
||||
|
||||
#[options(
|
||||
meta = "",
|
||||
help = "Set LED mode direction <forward, reverse> (does not apply to all)"
|
||||
)]
|
||||
pub direction: Option<Direction>,
|
||||
|
||||
#[options(
|
||||
meta = "",
|
||||
help = "Set LED colours <hex>, specify up to 4 with repeated arg"
|
||||
)]
|
||||
pub colours: Vec<Colour>,
|
||||
|
||||
#[options(help = "list available animations")]
|
||||
pub list: bool,
|
||||
}
|
||||
@@ -18,6 +18,7 @@ config-traits = { path = "../config-traits" }
|
||||
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
||||
rog_slash = { path = "../rog-slash", features = ["dbus"] }
|
||||
rog_aura = { path = "../rog-aura", features = ["dbus"] }
|
||||
rog_scsi = { path = "../rog-scsi", features = ["dbus"] }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
rog_profiles = { path = "../rog-profiles" }
|
||||
dmi_id = { path = "../dmi-id" }
|
||||
|
||||
@@ -18,6 +18,7 @@ use zbus::Connection;
|
||||
|
||||
use crate::aura_anime::trait_impls::AniMeZbus;
|
||||
use crate::aura_laptop::trait_impls::AuraZbus;
|
||||
use crate::aura_scsi::trait_impls::ScsiZbus;
|
||||
use crate::aura_slash::trait_impls::SlashZbus;
|
||||
use crate::aura_types::DeviceHandle;
|
||||
use crate::error::RogError;
|
||||
@@ -70,6 +71,17 @@ fn dbus_path_for_anime() -> OwnedObjectPath {
|
||||
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/anime")).into()
|
||||
}
|
||||
|
||||
fn dbus_path_for_scsi(prod_id: &str) -> OwnedObjectPath {
|
||||
ObjectPath::from_str_unchecked(&format!("{ASUS_ZBUS_PATH}/{prod_id}_scsi")).into()
|
||||
}
|
||||
|
||||
fn dev_prop_matches(dev: &Device, prop: &str, value: &str) -> bool {
|
||||
if let Some(p) = dev.property_value(prop) {
|
||||
return p == value;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - make this the HID manager (and universal)
|
||||
// - *really* need to make most of this actual kernel drivers
|
||||
@@ -83,7 +95,6 @@ fn dbus_path_for_anime() -> OwnedObjectPath {
|
||||
///
|
||||
/// Each controller within should track its dbus path so it can be removed if
|
||||
/// required.
|
||||
#[derive(Debug)]
|
||||
pub struct AsusDevice {
|
||||
device: DeviceHandle,
|
||||
dbus_path: OwnedObjectPath,
|
||||
@@ -197,7 +208,75 @@ impl DeviceManager {
|
||||
{
|
||||
devices.append(&mut Self::init_hid_devices(connection, device).await?);
|
||||
}
|
||||
// debug!("Found devices: {devices:?}");
|
||||
|
||||
Ok(devices)
|
||||
}
|
||||
|
||||
async fn init_scsi(
|
||||
connection: &Connection,
|
||||
device: &Device,
|
||||
path: OwnedObjectPath,
|
||||
) -> Option<AsusDevice> {
|
||||
// "ID_MODEL_ID" "1932"
|
||||
// "ID_VENDOR_ID" "0b05"
|
||||
if dev_prop_matches(&device, "ID_VENDOR_ID", "0b05") {
|
||||
if let Some(dev_node) = device.devnode() {
|
||||
let prod_id = device
|
||||
.property_value("ID_MODEL_ID")
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy();
|
||||
if let Ok(dev_type) =
|
||||
DeviceHandle::maybe_scsi(dev_node.as_os_str().to_str().unwrap(), &prod_id).await
|
||||
{
|
||||
if let DeviceHandle::Scsi(scsi) = dev_type.clone() {
|
||||
let ctrl = ScsiZbus::new(scsi);
|
||||
ctrl.start_tasks(connection, path.clone()).await.unwrap();
|
||||
return Some(AsusDevice {
|
||||
device: dev_type,
|
||||
dbus_path: path,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
async fn init_all_scsi(connection: &Connection) -> Result<Vec<AsusDevice>, RogError> {
|
||||
// track and ensure we use only one hidraw per prod_id
|
||||
// let mut interfaces = HashSet::new();
|
||||
let mut devices: Vec<AsusDevice> = Vec::new();
|
||||
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
|
||||
enumerator.match_subsystem("block").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
PlatformError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
let mut found = Vec::new();
|
||||
for device in enumerator
|
||||
.scan_devices()
|
||||
.map_err(|e| PlatformError::IoPath("enumerator".to_owned(), e))?
|
||||
{
|
||||
if let Some(serial) = device.property_value("ID_SERIAL_SHORT") {
|
||||
let serial = serial.to_string_lossy().to_string();
|
||||
let path = dbus_path_for_scsi(&serial);
|
||||
if found.contains(&path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if let Some(dev) = Self::init_scsi(connection, &device, path.clone()).await {
|
||||
devices.push(dev);
|
||||
found.push(path);
|
||||
}
|
||||
} else {
|
||||
warn!("No serial for SCSI device");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(devices)
|
||||
}
|
||||
@@ -252,6 +331,11 @@ impl DeviceManager {
|
||||
info!("Tested device was not AniMe Matrix");
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(devs) = &mut Self::init_all_scsi(connection).await {
|
||||
devices.append(devs);
|
||||
}
|
||||
|
||||
devices
|
||||
}
|
||||
|
||||
@@ -268,7 +352,7 @@ impl DeviceManager {
|
||||
// detect all plugged in aura devices (eventually)
|
||||
// only USB devices are detected for here
|
||||
std::thread::spawn(move || {
|
||||
let mut monitor = MonitorBuilder::new()?.match_subsystem("hidraw")?.listen()?;
|
||||
let mut monitor = MonitorBuilder::new()?.listen()?;
|
||||
let mut poll = Poll::new()?;
|
||||
let mut events = Events::with_capacity(1024);
|
||||
poll.registry()
|
||||
@@ -281,17 +365,74 @@ impl DeviceManager {
|
||||
continue;
|
||||
}
|
||||
for event in monitor.iter() {
|
||||
let action = event.action().unwrap_or_default();
|
||||
let action = event
|
||||
.action()
|
||||
.unwrap_or_default()
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
|
||||
let subsys = if let Some(subsys) = event.subsystem() {
|
||||
subsys.to_string_lossy().to_string()
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let devices = devices.clone();
|
||||
let conn_copy = conn_copy.clone();
|
||||
block_on(async move {
|
||||
// SCSCI devs
|
||||
if subsys == "block" {
|
||||
if action == "remove" {
|
||||
if let Some(serial) =
|
||||
event.device().property_value("ID_SERIAL_SHORT")
|
||||
{
|
||||
let serial = serial.to_string_lossy().to_string();
|
||||
let path = dbus_path_for_scsi(&serial);
|
||||
|
||||
let index = if let Some(index) = devices
|
||||
.lock()
|
||||
.await
|
||||
.iter()
|
||||
.position(|dev| dev.dbus_path == path)
|
||||
{
|
||||
index
|
||||
} else {
|
||||
warn!("No device for dbus path: {path:?}");
|
||||
return Ok(());
|
||||
};
|
||||
info!("removing: {path:?}");
|
||||
let dev = devices.lock().await.remove(index);
|
||||
let path = path.clone();
|
||||
match dev.device {
|
||||
DeviceHandle::Scsi(_) => {
|
||||
conn_copy
|
||||
.object_server()
|
||||
.remove::<ScsiZbus, _>(&path)
|
||||
.await?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else if action == "add" {
|
||||
let evdev = event.device();
|
||||
if let Some(serial) = evdev.property_value("ID_SERIAL_SHORT") {
|
||||
let serial = serial.to_string_lossy().to_string();
|
||||
let path = dbus_path_for_scsi(&serial);
|
||||
if let Some(new_devs) =
|
||||
Self::init_scsi(&conn_copy, &evdev, path).await
|
||||
{
|
||||
devices.lock().await.append(&mut vec![new_devs]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if subsys == "hidraw" {
|
||||
if let Some(parent) =
|
||||
event.parent_with_subsystem_devtype("usb", "usb_device")?
|
||||
{
|
||||
let devices = devices.clone();
|
||||
|
||||
if action == "remove" {
|
||||
if let Some(path) = dbus_path_for_dev(&parent) {
|
||||
let conn_copy = conn_copy.clone();
|
||||
tokio::spawn(async move {
|
||||
// Find the indexs of devices matching the path
|
||||
let removals: Vec<usize> = devices
|
||||
.lock()
|
||||
@@ -333,31 +474,34 @@ impl DeviceManager {
|
||||
.remove::<AniMeZbus, _>(&path)
|
||||
.await?
|
||||
}
|
||||
DeviceHandle::Ally(_) => todo!(),
|
||||
DeviceHandle::OldAura(_) => todo!(),
|
||||
DeviceHandle::TufLedClass(_) => todo!(),
|
||||
DeviceHandle::MulticolourLed => todo!(),
|
||||
DeviceHandle::None => todo!(),
|
||||
DeviceHandle::Scsi(_) => {
|
||||
conn_copy
|
||||
.object_server()
|
||||
.remove::<ScsiZbus, _>(&path)
|
||||
.await?
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
info!("AuraManager removed: {path:?}, {res}");
|
||||
}
|
||||
Ok::<(), RogError>(())
|
||||
});
|
||||
}
|
||||
} else if action == "add" {
|
||||
let evdev = event.device();
|
||||
let conn_copy = conn_copy.clone();
|
||||
block_on(async move {
|
||||
if let Ok(mut new_devs) = Self::init_hid_devices(&conn_copy, evdev)
|
||||
if let Ok(mut new_devs) =
|
||||
Self::init_hid_devices(&conn_copy, evdev)
|
||||
.await
|
||||
.map_err(|e| error!("Couldn't add new device: {e:?}"))
|
||||
{
|
||||
devices.lock().await.append(&mut new_devs);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok::<(), RogError>(())
|
||||
})
|
||||
.map_err(|e| error!("{e:?}"))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
// Required for return type on spawn
|
||||
#[allow(unreachable_code)]
|
||||
|
||||
114
asusd/src/aura_scsi/config.rs
Normal file
114
asusd/src/aura_scsi/config.rs
Normal file
@@ -0,0 +1,114 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use config_traits::{StdConfig, StdConfigLoad};
|
||||
use rog_aura::AuraDeviceType;
|
||||
use rog_scsi::{AuraEffect, AuraMode};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const CONFIG_FILE: &str = "scsi.ron";
|
||||
|
||||
/// Config for base system actions for the anime display
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
pub struct ScsiConfig {
|
||||
#[serde(skip)]
|
||||
pub dev_type: AuraDeviceType,
|
||||
pub enabled: bool,
|
||||
pub current_mode: AuraMode,
|
||||
pub modes: BTreeMap<AuraMode, AuraEffect>,
|
||||
}
|
||||
|
||||
impl ScsiConfig {
|
||||
pub fn get_effect(&mut self, mode: AuraMode) -> Option<&AuraEffect> {
|
||||
self.modes.get(&mode)
|
||||
}
|
||||
|
||||
pub fn save_effect(&mut self, effect: AuraEffect) {
|
||||
self.current_mode = effect.mode;
|
||||
self.modes.insert(*effect.mode(), effect);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ScsiConfig {
|
||||
fn default() -> Self {
|
||||
ScsiConfig {
|
||||
enabled: true,
|
||||
current_mode: AuraMode::Static,
|
||||
dev_type: AuraDeviceType::ScsiExtDisk,
|
||||
modes: BTreeMap::from([
|
||||
(AuraMode::Off, AuraEffect::default_with_mode(AuraMode::Off)),
|
||||
(
|
||||
AuraMode::Static,
|
||||
AuraEffect::default_with_mode(AuraMode::Static),
|
||||
),
|
||||
(
|
||||
AuraMode::Breathe,
|
||||
AuraEffect::default_with_mode(AuraMode::Breathe),
|
||||
),
|
||||
(
|
||||
AuraMode::Flashing,
|
||||
AuraEffect::default_with_mode(AuraMode::Flashing),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowCycle,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowCycle),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowWave,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowWave),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowCycleBreathe,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowCycleBreathe),
|
||||
),
|
||||
(
|
||||
AuraMode::ChaseFade,
|
||||
AuraEffect::default_with_mode(AuraMode::ChaseFade),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowCycleChaseFade,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowCycleChaseFade),
|
||||
),
|
||||
(
|
||||
AuraMode::Chase,
|
||||
AuraEffect::default_with_mode(AuraMode::Chase),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowCycleChase,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowCycleChase),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowCycleWave,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowCycleWave),
|
||||
),
|
||||
(
|
||||
AuraMode::RainbowPulseChase,
|
||||
AuraEffect::default_with_mode(AuraMode::RainbowPulseChase),
|
||||
),
|
||||
(
|
||||
AuraMode::RandomFlicker,
|
||||
AuraEffect::default_with_mode(AuraMode::RandomFlicker),
|
||||
),
|
||||
(
|
||||
AuraMode::DoubleFade,
|
||||
AuraEffect::default_with_mode(AuraMode::DoubleFade),
|
||||
),
|
||||
]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfig for ScsiConfig {
|
||||
fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
fn file_name(&self) -> String {
|
||||
CONFIG_FILE.to_owned()
|
||||
}
|
||||
|
||||
fn config_dir() -> std::path::PathBuf {
|
||||
std::path::PathBuf::from(crate::CONFIG_PATH_BASE)
|
||||
}
|
||||
}
|
||||
|
||||
impl StdConfigLoad for ScsiConfig {}
|
||||
45
asusd/src/aura_scsi/mod.rs
Normal file
45
asusd/src/aura_scsi/mod.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use config::ScsiConfig;
|
||||
use rog_scsi::{AuraEffect, Device, Task};
|
||||
use tokio::sync::{Mutex, MutexGuard};
|
||||
|
||||
use crate::error::RogError;
|
||||
|
||||
pub mod config;
|
||||
pub mod trait_impls;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ScsiAura {
|
||||
device: Arc<Mutex<Device>>,
|
||||
config: Arc<Mutex<ScsiConfig>>,
|
||||
}
|
||||
|
||||
impl ScsiAura {
|
||||
pub fn new(device: Arc<Mutex<Device>>, config: Arc<Mutex<ScsiConfig>>) -> Self {
|
||||
Self { device, config }
|
||||
}
|
||||
|
||||
pub async fn lock_config(&self) -> MutexGuard<ScsiConfig> {
|
||||
self.config.lock().await
|
||||
}
|
||||
|
||||
pub async fn write_effect(&self, effect: &AuraEffect) -> Result<(), RogError> {
|
||||
let tasks: Vec<Task> = effect.into();
|
||||
for task in &tasks {
|
||||
self.device.lock().await.perform(task).ok();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Initialise the device if required. Locks the internal config so be wary
|
||||
/// of deadlocks.
|
||||
pub async fn do_initialization(&self) -> Result<(), RogError> {
|
||||
let config = self.config.lock().await;
|
||||
let mode = config.current_mode;
|
||||
if let Some(effect) = config.modes.get(&mode) {
|
||||
self.write_effect(effect).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
116
asusd/src/aura_scsi/trait_impls.rs
Normal file
116
asusd/src/aura_scsi/trait_impls.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use config_traits::StdConfig;
|
||||
use log::error;
|
||||
use rog_aura::AuraDeviceType;
|
||||
use rog_scsi::{AuraEffect, AuraMode};
|
||||
use zbus::fdo::Error as ZbErr;
|
||||
use zbus::zvariant::OwnedObjectPath;
|
||||
use zbus::{interface, Connection};
|
||||
|
||||
use super::ScsiAura;
|
||||
use crate::error::RogError;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ScsiZbus(ScsiAura);
|
||||
|
||||
impl ScsiZbus {
|
||||
pub fn new(scsi: ScsiAura) -> Self {
|
||||
Self(scsi)
|
||||
}
|
||||
|
||||
pub async fn start_tasks(
|
||||
self,
|
||||
connection: &Connection,
|
||||
path: OwnedObjectPath,
|
||||
) -> Result<(), RogError> {
|
||||
connection
|
||||
.object_server()
|
||||
.at(path.clone(), self)
|
||||
.await
|
||||
.map_err(|e| error!("Couldn't add server at path: {path}, {e:?}"))
|
||||
.ok();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[interface(name = "org.asuslinux.ScsiAura")]
|
||||
impl ScsiZbus {
|
||||
/// Return the device type for this Aura keyboard
|
||||
#[zbus(property)]
|
||||
async fn device_type(&self) -> AuraDeviceType {
|
||||
self.0.config.lock().await.dev_type
|
||||
}
|
||||
|
||||
/// Get enabled or not
|
||||
#[zbus(property)]
|
||||
async fn enabled(&self) -> bool {
|
||||
let lock = self.0.lock_config().await;
|
||||
lock.enabled
|
||||
}
|
||||
|
||||
/// Set enabled true or false
|
||||
#[zbus(property)]
|
||||
async fn set_enabled(&self, enabled: bool) {
|
||||
let mut config = self.0.lock_config().await;
|
||||
config.enabled = enabled;
|
||||
config.write();
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn led_mode(&self) -> u8 {
|
||||
let config = self.0.lock_config().await;
|
||||
config.current_mode as u8
|
||||
}
|
||||
|
||||
#[zbus(property)]
|
||||
async fn set_led_mode(&self, mode: AuraMode) -> Result<(), zbus::Error> {
|
||||
let mut config = self.0.lock_config().await;
|
||||
if let Some(effect) = config.get_effect(mode) {
|
||||
self.0
|
||||
.write_effect(effect)
|
||||
.await
|
||||
.map_err(|e| zbus::Error::Failure(format!("{e:?}")))?;
|
||||
} else {
|
||||
return Err(zbus::Error::Failure("Mode data does not exist".to_string()));
|
||||
}
|
||||
config.current_mode = mode;
|
||||
config.write();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// The current mode data
|
||||
#[zbus(property)]
|
||||
async fn led_mode_data(&self) -> Result<AuraEffect, ZbErr> {
|
||||
// entirely possible to deadlock here, so use try instead of lock()
|
||||
if let Ok(config) = self.0.config.try_lock() {
|
||||
let mode = config.current_mode;
|
||||
match config.modes.get(&mode) {
|
||||
Some(effect) => Ok(effect.clone()),
|
||||
None => Err(ZbErr::Failed("Could not get the current effect".into())),
|
||||
}
|
||||
} else {
|
||||
Err(ZbErr::Failed("Aura control couldn't lock self".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Set an Aura effect if the effect mode or zone is supported.
|
||||
///
|
||||
/// On success the aura config file is read to refresh cached values, then
|
||||
/// the effect is stored and config written to disk.
|
||||
#[zbus(property)]
|
||||
async fn set_led_mode_data(&mut self, effect: AuraEffect) -> Result<(), ZbErr> {
|
||||
self.0.write_effect(&effect).await?;
|
||||
|
||||
let mut config = self.0.config.lock().await;
|
||||
config.save_effect(effect);
|
||||
config.write();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the data set for every mode available
|
||||
async fn all_mode_data(&self) -> BTreeMap<AuraMode, AuraEffect> {
|
||||
let config = self.0.config.lock().await;
|
||||
config.modes.clone()
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ use rog_aura::AuraDeviceType;
|
||||
use rog_platform::hid_raw::HidRaw;
|
||||
use rog_platform::keyboard_led::KeyboardBacklight;
|
||||
use rog_platform::usb_raw::USBRaw;
|
||||
use rog_scsi::{open_device, ScsiType};
|
||||
use rog_slash::error::SlashError;
|
||||
use rog_slash::SlashType;
|
||||
use tokio::sync::Mutex;
|
||||
@@ -17,6 +18,8 @@ use crate::aura_anime::config::AniMeConfig;
|
||||
use crate::aura_anime::AniMe;
|
||||
use crate::aura_laptop::config::AuraConfig;
|
||||
use crate::aura_laptop::Aura;
|
||||
use crate::aura_scsi::config::ScsiConfig;
|
||||
use crate::aura_scsi::ScsiAura;
|
||||
use crate::aura_slash::config::SlashConfig;
|
||||
use crate::aura_slash::Slash;
|
||||
use crate::error::RogError;
|
||||
@@ -31,12 +34,13 @@ pub enum _DeviceHandle {
|
||||
None,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub enum DeviceHandle {
|
||||
Aura(Aura),
|
||||
Slash(Slash),
|
||||
/// The AniMe devices require USBRaw as they are not HID devices
|
||||
AniMe(AniMe),
|
||||
Scsi(ScsiAura),
|
||||
Ally(Arc<Mutex<HidRaw>>),
|
||||
OldAura(Arc<Mutex<HidRaw>>),
|
||||
/// TUF laptops have an aditional set of attributes added to the LED /sysfs/
|
||||
@@ -146,6 +150,23 @@ impl DeviceHandle {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn maybe_scsi(dev_node: &str, prod_id: &str) -> Result<Self, RogError> {
|
||||
debug!("Testing for SCSI");
|
||||
let prod_id = ScsiType::from(prod_id);
|
||||
if prod_id == ScsiType::Unsupported {
|
||||
log::info!("Unknown or invalid SCSI: {prod_id:?}, skipping");
|
||||
return Err(RogError::NotFound("No SCSI device".to_string()));
|
||||
}
|
||||
info!("Found SCSI device {prod_id:?} on {dev_node}");
|
||||
|
||||
let mut config = ScsiConfig::new().load();
|
||||
config.dev_type = AuraDeviceType::ScsiExtDisk;
|
||||
let dev = Arc::new(Mutex::new(open_device(dev_node)?));
|
||||
let scsi = ScsiAura::new(dev, Arc::new(Mutex::new(config)));
|
||||
scsi.do_initialization().await?;
|
||||
Ok(Self::Scsi(scsi))
|
||||
}
|
||||
|
||||
pub async fn maybe_laptop_aura(
|
||||
device: Arc<Mutex<HidRaw>>,
|
||||
prod_id: &str,
|
||||
|
||||
@@ -9,6 +9,7 @@ pub mod ctrl_platform;
|
||||
pub mod aura_anime;
|
||||
pub mod aura_laptop;
|
||||
pub mod aura_manager;
|
||||
pub mod aura_scsi;
|
||||
pub mod aura_slash;
|
||||
pub mod aura_types;
|
||||
pub mod error;
|
||||
|
||||
@@ -494,56 +494,6 @@ impl Display for AuraEffect {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AuraParameters {
|
||||
pub zone: bool,
|
||||
pub colour1: bool,
|
||||
pub colour2: bool,
|
||||
pub speed: bool,
|
||||
pub direction: bool,
|
||||
}
|
||||
|
||||
#[allow(clippy::fn_params_excessive_bools)]
|
||||
impl AuraParameters {
|
||||
pub const fn new(
|
||||
zone: bool,
|
||||
colour1: bool,
|
||||
colour2: bool,
|
||||
speed: bool,
|
||||
direction: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
zone,
|
||||
colour1,
|
||||
colour2,
|
||||
speed,
|
||||
direction,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AuraEffect {
|
||||
/// A helper to provide detail on what effects have which parameters, e.g
|
||||
/// the static factory mode accepts only one colour.
|
||||
pub const fn allowed_parameters(mode: AuraModeNum) -> AuraParameters {
|
||||
match mode {
|
||||
AuraModeNum::Static
|
||||
| AuraModeNum::Highlight
|
||||
| AuraModeNum::Pulse
|
||||
| AuraModeNum::Comet
|
||||
| AuraModeNum::Flash => AuraParameters::new(true, true, false, false, false),
|
||||
AuraModeNum::Breathe => AuraParameters::new(true, true, true, true, false),
|
||||
AuraModeNum::RainbowCycle | AuraModeNum::Rain => {
|
||||
AuraParameters::new(true, false, false, true, false)
|
||||
}
|
||||
AuraModeNum::RainbowWave => AuraParameters::new(true, false, false, true, true),
|
||||
AuraModeNum::Star => AuraParameters::new(true, true, true, true, true),
|
||||
AuraModeNum::Laser | AuraModeNum::Ripple => {
|
||||
AuraParameters::new(true, true, false, true, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses `AuraEffect` in to packet data for writing to the USB interface
|
||||
///
|
||||
/// Byte structure where colour is RGB, one byte per R, G, B:
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"POT-Creation-Date: 2024-12-18 23:02+0000\n"
|
||||
"POT-Creation-Date: 2024-12-22 03:56+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
|
||||
@@ -13,6 +13,7 @@ description = "dbus interface methods for asusctl"
|
||||
asusd = { path = "../asusd" }
|
||||
rog_anime = { path = "../rog-anime", features = ["dbus"] }
|
||||
rog_slash = { path = "../rog-slash", features = ["dbus"] }
|
||||
rog_scsi = { path = "../rog-scsi", features = ["dbus"] }
|
||||
rog_aura = { path = "../rog-aura" }
|
||||
rog_profiles = { path = "../rog-profiles" }
|
||||
rog_platform = { path = "../rog-platform" }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub use asusd::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
|
||||
|
||||
pub mod scsi_aura;
|
||||
pub mod zbus_anime;
|
||||
pub mod zbus_aura;
|
||||
pub mod zbus_fan_curves;
|
||||
|
||||
56
rog-dbus/src/scsi_aura.rs
Normal file
56
rog-dbus/src/scsi_aura.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
//! # D-Bus interface proxy for: `org.asuslinux.ScsiAura`
|
||||
//!
|
||||
//! This code was generated by `zbus-xmlgen` `5.0.1` from D-Bus introspection
|
||||
//! data. Source: `Interface '/org/asuslinux/M3D0AP048745_scsi' from service
|
||||
//! 'org.asuslinux.Daemon' on system bus`.
|
||||
//!
|
||||
//! You may prefer to adapt it, instead of using it verbatim.
|
||||
//!
|
||||
//! More information can be found in the [Writing a client proxy] section of the
|
||||
//! zbus documentation.
|
||||
//!
|
||||
//! This type implements the [D-Bus standard interfaces],
|
||||
//! (`org.freedesktop.DBus.*`) for which the following zbus API can be used:
|
||||
//!
|
||||
//! * [`zbus::fdo::PeerProxy`]
|
||||
//! * [`zbus::fdo::PropertiesProxy`]
|
||||
//! * [`zbus::fdo::IntrospectableProxy`]
|
||||
//!
|
||||
//! Consequently `zbus-xmlgen` did not generate code for the above interfaces.
|
||||
//!
|
||||
//! [Writing a client proxy]: https://dbus2.github.io/zbus/client.html
|
||||
//! [D-Bus standard interfaces]: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces,
|
||||
use rog_scsi::{AuraEffect, AuraMode};
|
||||
use zbus::proxy;
|
||||
#[proxy(
|
||||
interface = "org.asuslinux.ScsiAura",
|
||||
default_service = "org.asuslinux.Daemon",
|
||||
default_path = "/org/asuslinux"
|
||||
)]
|
||||
pub trait ScsiAura {
|
||||
/// AllModeData method
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn all_mode_data(&self) -> zbus::Result<std::collections::HashMap<AuraMode, AuraEffect>>;
|
||||
|
||||
/// DeviceType property
|
||||
#[zbus(property)]
|
||||
fn device_type(&self) -> zbus::Result<u32>;
|
||||
|
||||
/// Enabled property
|
||||
#[zbus(property)]
|
||||
fn enabled(&self) -> zbus::Result<bool>;
|
||||
#[zbus(property)]
|
||||
fn set_enabled(&self, value: bool) -> zbus::Result<()>;
|
||||
|
||||
/// LedMode property
|
||||
#[zbus(property)]
|
||||
fn led_mode(&self) -> zbus::Result<u8>;
|
||||
#[zbus(property)]
|
||||
fn set_led_mode(&self, mode: AuraMode) -> zbus::Result<()>;
|
||||
|
||||
/// LedModeData property
|
||||
#[zbus(property)]
|
||||
fn led_mode_data(&self) -> zbus::Result<AuraEffect>;
|
||||
#[zbus(property)]
|
||||
fn set_led_mode_data(&self, effect: AuraEffect) -> zbus::Result<()>;
|
||||
}
|
||||
29
rog-scsi/Cargo.toml
Normal file
29
rog-scsi/Cargo.toml
Normal file
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "rog_scsi"
|
||||
version.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
[features]
|
||||
default = ["dbus", "ron"]
|
||||
dbus = ["zbus"]
|
||||
|
||||
[dependencies]
|
||||
sg.workspace = true
|
||||
serde.workspace = true
|
||||
zbus = { workspace = true, optional = true }
|
||||
|
||||
# cli and logging
|
||||
log.workspace = true
|
||||
typeshare.workspace = true
|
||||
|
||||
ron = { version = "*", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
cargo-husky.workspace = true
|
||||
398
rog-scsi/src/builtin_modes.rs
Normal file
398
rog-scsi/src/builtin_modes.rs
Normal file
@@ -0,0 +1,398 @@
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typeshare::typeshare;
|
||||
#[cfg(feature = "dbus")]
|
||||
use zbus::zvariant::{OwnedValue, Type, Value};
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::scsi::{apply_task, dir_task, mode_task, rgb_task, save_task, speed_task};
|
||||
|
||||
#[typeshare]
|
||||
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)]
|
||||
pub struct Colour {
|
||||
pub r: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
}
|
||||
|
||||
impl Default for Colour {
|
||||
fn default() -> Self {
|
||||
Colour { r: 166, g: 0, b: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Colour {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.len() < 6 {
|
||||
return Err(Error::ParseColour);
|
||||
}
|
||||
let r = u8::from_str_radix(&s[0..2], 16).or(Err(Error::ParseColour))?;
|
||||
let g = u8::from_str_radix(&s[2..4], 16).or(Err(Error::ParseColour))?;
|
||||
let b = u8::from_str_radix(&s[4..6], 16).or(Err(Error::ParseColour))?;
|
||||
Ok(Colour { r, g, b })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&[u8; 3]> for Colour {
|
||||
fn from(c: &[u8; 3]) -> Self {
|
||||
Self {
|
||||
r: c[0],
|
||||
g: c[1],
|
||||
b: c[2],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Colour> for [u8; 3] {
|
||||
fn from(c: Colour) -> Self {
|
||||
[c.r, c.b, c.g]
|
||||
}
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
#[cfg_attr(
|
||||
feature = "dbus",
|
||||
derive(Type, Value, OwnedValue),
|
||||
zvariant(signature = "u")
|
||||
)]
|
||||
pub enum Direction {
|
||||
#[default]
|
||||
Forward = 0,
|
||||
Reverse = 1,
|
||||
}
|
||||
|
||||
impl FromStr for Direction {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"forward" => Ok(Direction::Forward),
|
||||
"reverse" => Ok(Direction::Reverse),
|
||||
_ => Err(Error::ParseSpeed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Direction {
|
||||
fn from(dir: u8) -> Self {
|
||||
match dir {
|
||||
1 => Direction::Reverse,
|
||||
_ => Direction::Forward,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Direction> for u8 {
|
||||
fn from(d: Direction) -> Self {
|
||||
d as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[typeshare]
|
||||
#[cfg_attr(
|
||||
feature = "dbus",
|
||||
derive(Type, Value, OwnedValue),
|
||||
zvariant(signature = "s")
|
||||
)]
|
||||
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum Speed {
|
||||
Slowest = 4,
|
||||
Slow = 3,
|
||||
#[default]
|
||||
Med = 2,
|
||||
Fast = 1,
|
||||
Fastest = 0,
|
||||
}
|
||||
|
||||
impl FromStr for Speed {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"slowest" => Ok(Speed::Slowest),
|
||||
"slow" => Ok(Speed::Slow),
|
||||
"med" => Ok(Speed::Med),
|
||||
"fast" => Ok(Speed::Fast),
|
||||
"fastest" => Ok(Speed::Fastest),
|
||||
_ => Err(Error::ParseSpeed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Speed> for u8 {
|
||||
fn from(s: Speed) -> u8 {
|
||||
match s {
|
||||
Speed::Slowest => 4,
|
||||
Speed::Slow => 3,
|
||||
Speed::Med => 2,
|
||||
Speed::Fast => 1,
|
||||
Speed::Fastest => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for Speed {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
4 => Self::Slowest,
|
||||
3 => Self::Slow,
|
||||
1 => Self::Fast,
|
||||
0 => Self::Fastest,
|
||||
_ => Self::Med,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Enum of modes that convert to the actual number required by a USB HID packet
|
||||
#[typeshare]
|
||||
#[cfg_attr(
|
||||
feature = "dbus",
|
||||
derive(Type, Value, OwnedValue),
|
||||
zvariant(signature = "u")
|
||||
)]
|
||||
#[derive(
|
||||
Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Deserialize, Serialize,
|
||||
)]
|
||||
pub enum AuraMode {
|
||||
Off = 0,
|
||||
#[default]
|
||||
Static = 1,
|
||||
Breathe = 2,
|
||||
Flashing = 3,
|
||||
RainbowCycle = 4,
|
||||
RainbowWave = 5,
|
||||
RainbowCycleBreathe = 6,
|
||||
ChaseFade = 7,
|
||||
RainbowCycleChaseFade = 8,
|
||||
Chase = 9,
|
||||
RainbowCycleChase = 10,
|
||||
RainbowCycleWave = 11,
|
||||
RainbowPulseChase = 12,
|
||||
RandomFlicker = 13,
|
||||
DoubleFade = 14,
|
||||
}
|
||||
|
||||
impl AuraMode {
|
||||
pub fn list() -> [String; 15] {
|
||||
[
|
||||
AuraMode::Off.to_string(),
|
||||
AuraMode::Static.to_string(),
|
||||
AuraMode::Breathe.to_string(),
|
||||
AuraMode::Flashing.to_string(),
|
||||
AuraMode::RainbowCycle.to_string(),
|
||||
AuraMode::RainbowWave.to_string(),
|
||||
AuraMode::RainbowCycleBreathe.to_string(),
|
||||
AuraMode::ChaseFade.to_string(),
|
||||
AuraMode::RainbowCycleChaseFade.to_string(),
|
||||
AuraMode::Chase.to_string(),
|
||||
AuraMode::RainbowCycleChase.to_string(),
|
||||
AuraMode::RainbowCycleWave.to_string(),
|
||||
AuraMode::RainbowPulseChase.to_string(),
|
||||
AuraMode::RandomFlicker.to_string(),
|
||||
AuraMode::DoubleFade.to_string(),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AuraMode {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", <&str>::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuraMode> for String {
|
||||
fn from(mode: AuraMode) -> Self {
|
||||
<&str>::from(&mode).to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AuraMode> for &str {
|
||||
fn from(mode: &AuraMode) -> Self {
|
||||
match mode {
|
||||
AuraMode::Off => "Off",
|
||||
AuraMode::Static => "Static",
|
||||
AuraMode::Breathe => "Breathe",
|
||||
AuraMode::RainbowCycle => "RainbowCycle",
|
||||
AuraMode::RainbowWave => "RainbowWave",
|
||||
AuraMode::Flashing => "Flashing",
|
||||
AuraMode::RainbowCycleBreathe => "RainbowCycleBreathe",
|
||||
AuraMode::ChaseFade => "ChaseFade",
|
||||
AuraMode::RainbowCycleChaseFade => "RainbowCycleChaseFade",
|
||||
AuraMode::Chase => "Chase",
|
||||
AuraMode::RainbowCycleChase => "RainbowCycleChase",
|
||||
AuraMode::RainbowCycleWave => "RainbowCycleWave",
|
||||
AuraMode::RainbowPulseChase => "RainbowPulseChase",
|
||||
AuraMode::RandomFlicker => "RandomFlicker",
|
||||
AuraMode::DoubleFade => "DoubleFade",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for AuraMode {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(mode: &str) -> Result<Self, Self::Err> {
|
||||
match mode {
|
||||
"Off" => Ok(Self::Off),
|
||||
"Static" => Ok(Self::Static),
|
||||
"Breathe" => Ok(Self::Breathe),
|
||||
"RainbowCycle" => Ok(Self::RainbowCycle),
|
||||
"RainbowWave" => Ok(Self::RainbowWave),
|
||||
"Flashing" => Ok(Self::Flashing),
|
||||
"RainbowCycleBreathe" => Ok(Self::RainbowCycleBreathe),
|
||||
"ChaseFade" => Ok(Self::ChaseFade),
|
||||
"RainbowCycleChaseFade" => Ok(Self::RainbowCycleChaseFade),
|
||||
"Chase" => Ok(Self::Chase),
|
||||
"RainbowCycleChase" => Ok(Self::RainbowCycleChase),
|
||||
"RainbowCycleWave" => Ok(Self::RainbowCycleWave),
|
||||
"RainbowPulseChase" => Ok(Self::RainbowPulseChase),
|
||||
"RandomFlicker" => Ok(Self::RandomFlicker),
|
||||
"DoubleFade" => Ok(Self::DoubleFade),
|
||||
_ => Err(Error::ParseMode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for AuraMode {
|
||||
fn from(mode: &str) -> Self {
|
||||
AuraMode::from_str(mode).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for AuraMode {
|
||||
fn from(mode: u8) -> Self {
|
||||
match mode {
|
||||
0 => Self::Off,
|
||||
1 => Self::Static,
|
||||
2 => Self::Breathe,
|
||||
3 => Self::Flashing,
|
||||
4 => Self::RainbowCycle,
|
||||
5 => Self::RainbowWave,
|
||||
6 => Self::RainbowCycleBreathe,
|
||||
7 => Self::ChaseFade,
|
||||
8 => Self::RainbowCycleChaseFade,
|
||||
9 => Self::Chase,
|
||||
10 => Self::RainbowCycleChase,
|
||||
11 => Self::RainbowCycleWave,
|
||||
12 => Self::RainbowPulseChase,
|
||||
13 => Self::RandomFlicker,
|
||||
14 => Self::DoubleFade,
|
||||
_ => Self::Static,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AuraEffect> for AuraMode {
|
||||
fn from(value: AuraEffect) -> Self {
|
||||
value.mode
|
||||
}
|
||||
}
|
||||
|
||||
/// Default factory modes structure.
|
||||
#[typeshare]
|
||||
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||
pub struct AuraEffect {
|
||||
/// The effect type
|
||||
pub mode: AuraMode,
|
||||
/// One of three speeds for modes that support speed (most that animate)
|
||||
pub speed: Speed,
|
||||
/// Up, down, left, right. Only Rainbow mode seems to use this
|
||||
pub direction: Direction,
|
||||
/// Primary colour for all modes
|
||||
pub colour1: Colour,
|
||||
/// Secondary colour in some modes like Breathing or Stars
|
||||
pub colour2: Colour,
|
||||
pub colour3: Colour,
|
||||
pub colour4: Colour,
|
||||
}
|
||||
|
||||
impl AuraEffect {
|
||||
pub fn mode(&self) -> &AuraMode {
|
||||
&self.mode
|
||||
}
|
||||
|
||||
pub fn mode_name(&self) -> &str {
|
||||
<&str>::from(&self.mode)
|
||||
}
|
||||
|
||||
pub fn mode_num(&self) -> u8 {
|
||||
self.mode as u8
|
||||
}
|
||||
|
||||
pub fn default_with_mode(mode: AuraMode) -> Self {
|
||||
Self {
|
||||
mode,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AuraEffect {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: AuraMode::Static,
|
||||
colour1: Colour { r: 166, g: 0, b: 0 },
|
||||
colour2: Colour { r: 0, g: 0, b: 0 },
|
||||
colour3: Colour { r: 166, g: 0, b: 0 },
|
||||
colour4: Colour { r: 0, g: 0, b: 0 },
|
||||
speed: Speed::Med,
|
||||
direction: Direction::Forward,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for AuraEffect {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
writeln!(f, "AuraEffect {{")?;
|
||||
writeln!(f, " mode: {}", self.mode())?;
|
||||
writeln!(f, " speed: {:?}", self.speed)?;
|
||||
writeln!(f, " direction: {:?}", self.direction)?;
|
||||
writeln!(f, " colour1: {:?}", self.colour1)?;
|
||||
writeln!(f, " colour2: {:?}", self.colour2)?;
|
||||
writeln!(f, " colour3: {:?}", self.colour3)?;
|
||||
writeln!(f, " colour4: {:?}", self.colour4)?;
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&AuraEffect> for Vec<sg::Task> {
|
||||
fn from(effect: &AuraEffect) -> Self {
|
||||
let mut tasks = Vec::new();
|
||||
|
||||
tasks.append(&mut vec![
|
||||
mode_task(effect.mode as u8),
|
||||
rgb_task(0, &effect.colour1.into()),
|
||||
rgb_task(1, &effect.colour2.into()),
|
||||
rgb_task(2, &effect.colour3.into()),
|
||||
rgb_task(3, &effect.colour4.into()),
|
||||
]);
|
||||
|
||||
if !matches!(effect.mode, AuraMode::Static | AuraMode::Off) {
|
||||
tasks.push(speed_task(effect.speed as u8));
|
||||
}
|
||||
if matches!(
|
||||
effect.mode,
|
||||
AuraMode::RainbowWave
|
||||
| AuraMode::ChaseFade
|
||||
| AuraMode::RainbowCycleChaseFade
|
||||
| AuraMode::Chase
|
||||
| AuraMode::RainbowCycleChase
|
||||
| AuraMode::RainbowCycleWave
|
||||
| AuraMode::RainbowPulseChase
|
||||
) {
|
||||
tasks.push(dir_task(effect.direction as u8));
|
||||
}
|
||||
|
||||
tasks.append(&mut vec![apply_task(), save_task()]);
|
||||
tasks
|
||||
}
|
||||
}
|
||||
41
rog-scsi/src/error.rs
Normal file
41
rog-scsi/src/error.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use std::{error, fmt};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ParseMode,
|
||||
ParseColour,
|
||||
ParseSpeed,
|
||||
ParseDirection,
|
||||
IoPath(String, std::io::Error),
|
||||
Ron(ron::Error),
|
||||
RonParse(ron::error::SpannedError),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Error::ParseColour => write!(f, "Could not parse colour"),
|
||||
Error::ParseSpeed => write!(f, "Could not parse speed"),
|
||||
Error::ParseDirection => write!(f, "Could not parse direction"),
|
||||
Error::ParseMode => write!(f, "Could not parse mode"),
|
||||
Error::IoPath(path, io) => write!(f, "IO Error: {path}, {io}"),
|
||||
Error::Ron(e) => write!(f, "RON Parse Error: {e}"),
|
||||
Error::RonParse(e) => write!(f, "RON Parse Error: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
|
||||
impl From<ron::Error> for Error {
|
||||
fn from(e: ron::Error) -> Self {
|
||||
Self::Ron(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ron::error::SpannedError> for Error {
|
||||
fn from(e: ron::error::SpannedError) -> Self {
|
||||
Self::RonParse(e)
|
||||
}
|
||||
}
|
||||
48
rog-scsi/src/lib.rs
Normal file
48
rog-scsi/src/lib.rs
Normal file
@@ -0,0 +1,48 @@
|
||||
mod builtin_modes;
|
||||
mod error;
|
||||
mod scsi;
|
||||
|
||||
pub use builtin_modes::*;
|
||||
pub use error::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use sg::{Device, Task};
|
||||
|
||||
pub const PROD_SCSI_ARION: &str = "1932";
|
||||
|
||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
||||
pub enum ScsiType {
|
||||
Arion,
|
||||
#[default]
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
impl ScsiType {
|
||||
pub const fn prod_id_str(&self) -> &str {
|
||||
match self {
|
||||
ScsiType::Arion => PROD_SCSI_ARION,
|
||||
ScsiType::Unsupported => "",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ScsiType {
|
||||
fn from(s: &str) -> Self {
|
||||
match s.to_lowercase().as_str() {
|
||||
PROD_SCSI_ARION | "0x1932" => Self::Arion,
|
||||
_ => Self::Unsupported,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ScsiType> for &str {
|
||||
fn from(s: ScsiType) -> Self {
|
||||
match s {
|
||||
ScsiType::Arion => PROD_SCSI_ARION,
|
||||
ScsiType::Unsupported => "Unsupported",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_device(path: &str) -> Result<Device, std::io::Error> {
|
||||
Device::open(path)
|
||||
}
|
||||
80
rog-scsi/src/scsi.rs
Normal file
80
rog-scsi/src/scsi.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
extern crate sg;
|
||||
|
||||
pub use sg::Task;
|
||||
|
||||
static ENE_APPLY_VAL: u8 = 0x01; // Value for Apply Changes Register
|
||||
static ENE_SAVE_VAL: u8 = 0xaa;
|
||||
|
||||
static ENE_REG_MODE: u32 = 0x8021; // Mode Selection Register
|
||||
static ENE_REG_SPEED: u32 = 0x8022; // Speed Control Register
|
||||
static ENE_REG_DIRECTION: u32 = 0x8023; // Direction Control Register
|
||||
|
||||
static ENE_REG_APPLY: u32 = 0x80a0;
|
||||
static _ENE_REG_COLORS_DIRECT_V2: u32 = 0x8100; // to read the colurs
|
||||
static ENE_REG_COLORS_EFFECT_V2: u32 = 0x8160;
|
||||
|
||||
fn data(reg: u32, arg_count: u8) -> [u8; 16] {
|
||||
let mut cdb = [0u8; 16];
|
||||
cdb[0] = 0xec;
|
||||
cdb[1] = 0x41;
|
||||
cdb[2] = 0x53;
|
||||
cdb[3] = ((reg >> 8) & 0x00ff) as u8;
|
||||
cdb[4] = (reg & 0x00ff) as u8;
|
||||
cdb[5] = 0x00;
|
||||
cdb[6] = 0x00;
|
||||
cdb[7] = 0x00;
|
||||
cdb[8] = 0x00;
|
||||
cdb[9] = 0x00;
|
||||
cdb[10] = 0x00;
|
||||
cdb[11] = 0x00;
|
||||
cdb[12] = 0x00;
|
||||
cdb[13] = arg_count; // how many u8 in data packet
|
||||
cdb[14] = 0x00;
|
||||
cdb[15] = 0x00;
|
||||
cdb
|
||||
}
|
||||
|
||||
pub(crate) fn rgb_task(led: u32, rgb: &[u8; 3]) -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(led * 3 + ENE_REG_COLORS_EFFECT_V2, 3).as_slice());
|
||||
task.set_data(rgb, sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
|
||||
/// 0-13
|
||||
pub(crate) fn mode_task(mode: u8) -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(ENE_REG_MODE, 1).as_slice());
|
||||
task.set_data(&[mode.min(13)], sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
|
||||
/// 0-4, fast to slow
|
||||
pub(crate) fn speed_task(speed: u8) -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(ENE_REG_SPEED, 1).as_slice());
|
||||
task.set_data(&[speed.min(4)], sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
|
||||
/// 0 = forward, 1 = backward
|
||||
pub(crate) fn dir_task(mode: u8) -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(ENE_REG_DIRECTION, 1).as_slice());
|
||||
task.set_data(&[mode.min(1)], sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
|
||||
pub(crate) fn apply_task() -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(ENE_REG_APPLY, 1).as_slice());
|
||||
task.set_data(&[ENE_APPLY_VAL], sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
|
||||
pub(crate) fn save_task() -> Task {
|
||||
let mut task = Task::new();
|
||||
task.set_cdb(data(ENE_REG_APPLY, 1).as_slice());
|
||||
task.set_data(&[ENE_SAVE_VAL], sg::Direction::ToDevice);
|
||||
task
|
||||
}
|
||||
Reference in New Issue
Block a user