Compare commits

...

40 Commits

Author SHA1 Message Date
Rob Parker
469d86bbc9 Merge branch 'fix/one-shot-charge-persistence' into 'main'
fix: one-shot charging loses original charge limit after restart

See merge request asus-linux/asusctl!242
2026-01-05 06:32:52 +00:00
bitr8
aa063c20fd fix: persist base_charge_control_end_threshold for one-shot charging
base_charge_control_end_threshold was marked #[serde(skip)] so it only
lived in memory. triggering one-shot charge then restarting asusd would
permanently lose the original charge limit.

- remove #[serde(skip)] so the field gets persisted
- add serde default of 0 for backwards compat (skips restore for
  upgraded configs missing the field)
- add comments explaining Default vs serde default asymmetry
2026-01-05 17:23:59 +11:00
Denis Benato
d03d8ce67f Release: v6.2.0 2025-12-13 14:41:12 +01:00
Denis Benato
ae3693e0d9 Feat: add aura support for G614F models 2025-12-13 14:17:49 +01:00
Denis Benato
c8b9248eda Chore: update CHANGELOG.md 2025-12-13 13:56:46 +01:00
Denis Benato
22098794fe Fix: ensure upper/lower case doesn't fail the match 2025-12-13 13:48:33 +01:00
Denis Benato
10d49f4fc8 Fix: rever silly change in anime type detection 2025-12-13 13:46:29 +01:00
Denis Benato
5aba2854b0 Feat: add support for GU605C* models 2025-12-13 13:45:55 +01:00
Denis Benato
ea32ad6e0a Feat: add support for FX607V 2025-12-13 13:36:46 +01:00
Denis Benato
ee0e612c04 Feat: add AniMe support for G835LW 2025-12-13 13:35:56 +01:00
Denis Benato
e565ce748a Feat: GA403WR -> GA403W 2025-12-13 13:21:58 +01:00
Denis Benato
7024941663 Chore: fix changelog styling 2025-12-13 13:14:37 +01:00
Denis Benato
817a0165b5 Merge branch 'ga403wr' into 'devel'
add support for ga403wr, zephyrus g14 2025

See merge request asus-linux/asusctl!235
2025-12-13 12:14:19 +00:00
Denis Benato
efcd038f40 Merge branch 'main' into 'devel'
Fix: restore spec file for fedora copr builds

See merge request asus-linux/asusctl!236
2025-12-13 12:06:36 +00:00
Ali
375d99b8fc Fix: restore spec file for fedora copr builds 2025-12-13 12:06:36 +00:00
rustysec
574b954866 add support for ga403wr, zephyrus g14 2025 2025-11-29 23:49:24 -08:00
Denis Benato
a811f20f65 Release: v6.1.22 2025-11-29 02:57:34 +01:00
Denis Benato
0c9c263be6 Chore: update CHANGELOG.md 2025-11-29 02:52:27 +01:00
Denis Benato
6571c04bfe Merge branch 'devel' 2025-11-29 02:51:29 +01:00
Denis Benato
e48acbb8a2 Chore: update CHANGELOG.md 2025-11-29 02:51:16 +01:00
Denis Benato
f33496ef68 Merge branch 'main' into 'main'
Support the ROG Strix G18 (2025) G815

See merge request asus-linux/asusctl!234
2025-11-29 01:50:33 +00:00
Denis Benato
cd3176b565 Feat: improve a debug message 2025-11-29 02:48:22 +01:00
Denis Benato
7595613d7e Fix: add EXPERTBOOK to udev rules 2025-11-29 02:00:23 +01:00
Adam Bierman
b8d0245e7a Support G815L 2025-11-27 03:20:26 +00:00
Adam Bierman
54bd2ec800 Update file aura_support.ron 2025-11-27 02:44:30 +00:00
Denis Benato
b6c8566565 Feat: Treat dGPU attributes the same as PPT attributes for power-profile 2025-11-23 17:12:55 +01:00
Denis Benato
052c096014 Fix: use the correct name for nv_tgp 2025-11-23 16:56:47 +01:00
Denis Benato
81cbe3c522 Chore(Makefile): install cargo-vendor-filterer 2025-11-20 14:04:35 +01:00
Denis Benato
09f7492bec Release: fuck fedora 2025-11-20 02:59:41 +01:00
Denis Benato
6adfb2cf48 Fix: Release process 2025-11-18 23:03:58 +01:00
Denis Benato
a2a56792a8 Chore: changelog for 6.1.20 2025-11-18 22:56:42 +01:00
Denis Benato
317daf4ed1 Release: 6.1.20 2025-11-18 22:50:35 +01:00
Denis Benato
eb0d9514b5 Merge branch 'devel' 2025-11-18 22:36:27 +01:00
LucaP
d324b1bce5 Feat: Added support for G635L* models. Lightbar, Logo, Matrix 2025-11-18 22:32:49 +01:00
Denis Benato
d1c7385146 Merge branch 'main' into 'main'
Feat: Added support for G635L* models. Lightbar, Logo, Matrix

See merge request asus-linux/asusctl!233
2025-11-18 21:31:13 +00:00
Denis Benato
48a4935fc7 Fix: don't spam the console 2025-11-18 21:36:48 +01:00
LucaP
7e917b91a5 Feat: Added support for G635L* models. Lightbar, Logo, Matrix 2025-11-17 20:12:30 +02:00
Denis Benato
45f8b8ffb0 Chore: attempt another CI fix 2025-11-16 14:43:40 +01:00
Denis Benato
031a36242b Chore: Spare memory on CI 2025-11-16 14:17:24 +01:00
Denis Benato
8ad26ad136 Fix: CI testing 2025-11-15 18:57:14 +01:00
22 changed files with 1138 additions and 486 deletions

View File

@@ -1,22 +1,26 @@
image: rust:latest
# Use shallow clone to reduce checkout size
variables:
GIT_DEPTH: "1"
# Put cargo home and target under project dir so we can clean them easily
CARGO_HOME: "$CI_PROJECT_DIR/.cargo"
CARGO_TARGET_DIR: "$CI_PROJECT_DIR/ci-target"
GIT_SUBMODULE_STRATEGY: normal
# Cache only cargo registries/git metadata to speed dependency fetches.
# Avoid caching compiled `target` artifacts which are large and easily fill disk.
.rust_cache: &rust_cache
cache:
# key: $CI_COMMIT_REF_SLUG
key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
paths:
# Don't include `incremental` to save space
# Debug
- target/debug/build/
- target/debug/deps/
- target/debug/.fingerprint/
- target/debug/.cargo-lock
# Release
- target/release/build/
- target/release/deps/
- target/release/.fingerprint/
- target/release/.cargo-lock
- .cargo/registry
- .cargo/git
before_script:
- df -h
- echo "Cleaning stale targets to free space if present"
- rm -rf "$CI_PROJECT_DIR/target" "$CI_PROJECT_DIR/ci-target" || true
- apt-get update -qq && apt-get install -y -qq libudev-dev libgtk-3-dev grep llvm clang libclang-dev libsdl2-dev libsdl2-gfx-dev
stages:
@@ -33,6 +37,9 @@ format:
script:
- rustup component add rustfmt || true
- cargo fmt --check
after_script:
- du -sh "$CI_PROJECT_DIR/ci-target" || true
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
check:
except:
@@ -44,6 +51,8 @@ check:
# deny currently catches too much
#- cargo install cargo-deny && cargo deny
- cargo install cargo-cranky && cargo cranky
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
test:
except:
@@ -52,6 +61,8 @@ test:
script:
- mkdir -p .git/hooks > /dev/null
- cargo test --locked --all
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true
release:
only:
@@ -59,11 +70,15 @@ release:
<<: *rust_cache
script:
- cargo install cargo-vendor-filterer
- cargo fetch
- make FROZEN=1 && make vendor
artifacts:
paths:
- vendor_asusctl*.tar.xz
- cargo-config
expire_in: 1 week
after_script:
- rm -rf vendor vendor_asusctl*.tar.xz "$CI_PROJECT_DIR/ci-target" || true
pages:
stage: deploy
@@ -74,11 +89,11 @@ pages:
- cargo doc --locked --document-private-items --no-deps --workspace
- rm -rf public
- mkdir public
- cp -R target/doc/* public
- cp -R ci-target/doc/* public
- cp extra/index.html public
artifacts:
paths:
- public
variables:
GIT_SUBMODULE_STRATEGY: normal
expire_in: 1 week
after_script:
- rm -rf "$CI_PROJECT_DIR/ci-target" || true

View File

@@ -2,6 +2,35 @@
## [Unreleased]
## [6.2.0]
## Changed
- Added aura support for FX607V: thanks @jomp16
- Added testing support for G835LW
- Added support for GU605C models slash lighting: thanks @Otters
- Restore fedora: thanks @ali205412
- Add support to G614F models slash lighting
## [6.1.22]
### Changed
- Allow configuration of nv_tgp
- Treat dGPU attributes as power profiles
- Add EXPERTBOOK DMI match to ensure the service is loaded
- Support G815L thanks to @solost !
## [6.1.21]
### Changed
- Kill Fedora: screw your cursed cargo bullshit
- Restore CI building
## [6.1.20]
### Changed
- Addded support for G635L: thanks @luca_pisl !
- Suppress verbose output in applications too, not just daemon
## [6.1.18]
### Changed

813
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
[workspace.package]
version = "6.1.18"
version = "6.2.0"
rust-version = "1.82"
license = "MPL-2.0"
readme = "README.md"
@@ -57,12 +57,12 @@ glam = { version = "^0.22", features = ["serde"] }
gumdrop = "^0.8"
udev = { version = "^0.8", features = ["mio"] }
rusb = "^0.9"
inotify = "^0.10.0"
inotify = "^0.10"
png_pong = "^0.8"
pix = "^0.13"
tinybmp = "^0.4.0"
gif = "^0.12.0"
tinybmp = "^0.4"
gif = "^0.12"
versions = "6.2"

View File

@@ -158,6 +158,8 @@ vendor:
mv .cargo/config ./cargo-config
rm -rf .cargo
rm -rf vendor
# Ensure cargo-vendor-filterer is installed (CI installs it already)
command -v cargo-vendor-filterer >/dev/null 2>&1 || cargo install --locked cargo-vendor-filterer
cargo vendor-filterer --all-features --platform x86_64-unknown-linux-gnu vendor
tar pcfJ vendor_asusctl_$(VERSION).tar.xz vendor
rm -rf vendor

View File

@@ -9,7 +9,7 @@ use aura_cli::{LedPowerCommand1, LedPowerCommand2};
use dmi_id::DMIID;
use fan_curve_cli::FanCurveCommand;
use gumdrop::{Opt, Options};
use log::{error, info};
use log::{error, info, LevelFilter};
use rog_anime::usb::get_anime_type;
use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType, Vec2};
use rog_aura::keyboard::{AuraPowerState, LaptopAuraPower};
@@ -44,12 +44,16 @@ mod scsi_cli;
mod slash_cli;
fn main() {
// Ensure tracing spans are quiet by default unless user overrides
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "warn,tracing=error,zbus=error");
}
let mut logger = env_logger::Builder::new();
logger
.parse_default_env()
.target(env_logger::Target::Stdout)
.filter_level(LevelFilter::Info)
.target(env_logger::Target::Stderr)
.format_timestamp(None)
.filter_level(log::LevelFilter::Debug)
.init();
let self_version = env!("CARGO_PKG_VERSION");

View File

@@ -170,7 +170,9 @@ impl crate::Reloadable for AsusArmouryAttribute {
info!("Reloading {}", self.attr.name());
let name: FirmwareAttribute = self.attr.name().into();
if name.is_ppt() {
// Treat dGPU attributes the same as PPT attributes for power-profile
// behaviour so they follow AC/DC tuning groups.
if name.is_ppt() || name.is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -277,7 +279,7 @@ impl AsusArmouryAttribute {
async fn restore_default(&self) -> fdo::Result<()> {
self.attr.restore_default()?;
if self.name().is_ppt() {
if self.name().is_ppt() || self.name().is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -336,7 +338,7 @@ impl AsusArmouryAttribute {
#[zbus(property)]
async fn current_value(&self) -> fdo::Result<i32> {
if self.name().is_ppt() {
if self.name().is_ppt() || self.name().is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -369,86 +371,9 @@ impl AsusArmouryAttribute {
))
}
async fn stored_value_for_power(&self, on_ac: bool) -> fdo::Result<i32> {
if !self.name().is_ppt() {
return Err(fdo::Error::NotSupported(
"Stored values are only available for PPT attributes".to_string(),
));
}
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let config = self.config.lock().await;
if let Some(tuning) = config.select_tunings_ref(on_ac, profile) {
if let Some(tune) = tuning.group.get(&self.name()) {
return Ok(*tune);
}
}
if let AttrValue::Integer(i) = self.attr.default_value() {
return Ok(*i);
}
Err(fdo::Error::Failed(
"Could not read stored value".to_string(),
))
}
async fn set_value_for_power(&mut self, on_ac: bool, value: i32) -> fdo::Result<()> {
if !self.name().is_ppt() {
return Err(fdo::Error::NotSupported(
"Setting stored values is only supported for PPT attributes".to_string(),
));
}
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let apply_now;
{
let mut config = self.config.lock().await;
let tuning = config.select_tunings(on_ac, profile);
if let Some(tune) = tuning.group.get_mut(&self.name()) {
*tune = value;
} else {
tuning.group.insert(self.name(), value);
debug!(
"Store {} value for {} power = {}",
self.attr.name(),
if on_ac { "AC" } else { "DC" },
value
);
}
apply_now = tuning.enabled;
config.write();
}
if apply_now {
let power_plugged = self
.power
.get_online()
.map_err(|e| {
error!("Could not get power status: {e:?}");
e
})
.unwrap_or_default()
!= 0;
if power_plugged == on_ac {
self.attr
.set_current_value(&AttrValue::Integer(value))
.map_err(|e| {
error!("Could not set value: {e:?}");
e
})?;
}
}
Ok(())
}
#[zbus(property)]
async fn set_current_value(&mut self, value: i32) -> fdo::Result<()> {
if self.name().is_ppt() {
if self.name().is_ppt() || self.name().is_dgpu() {
let profile: PlatformProfile = self.platform.get_platform_profile()?.into();
let power_plugged = self
.power
@@ -538,8 +463,7 @@ pub async fn start_attributes_zbus(
"Skipping attribute '{}' due to reload error: {e:?}",
attr.attr.name()
);
// continue with others
continue;
break;
}
let attr_name = attr.attribute_name();
@@ -577,7 +501,7 @@ pub async fn set_config_or_default(
) {
for attr in attrs.attributes().iter() {
let name: FirmwareAttribute = attr.name().into();
if name.is_ppt() {
if name.is_ppt() || name.is_dgpu() {
let tuning = config.select_tunings(power_plugged, profile);
if !tuning.enabled {
debug!("Tuning group is not enabled, skipping");

View File

@@ -132,7 +132,7 @@ impl DeviceManager {
if let Some(usb_id) = usb_device.attribute_value("idProduct") {
if let Some(vendor_id) = usb_device.attribute_value("idVendor") {
if vendor_id != "0b05" {
debug!("Not ASUS vendor ID");
debug!("Not ASUS vendor ID: {}", vendor_id.to_string_lossy());
return Ok(devices);
}
// Almost all devices are identified by the productId.

View File

@@ -8,6 +8,12 @@ use serde::{Deserialize, Serialize};
const CONFIG_FILE: &str = "asusd.ron";
/// Default value for base_charge_control_end_threshold when not present in config.
/// Returns 0 so restore_charge_limit() skips restoration for upgraded configs.
fn default_base_charge_limit() -> u8 {
0
}
#[derive(Default, Clone, Deserialize, Serialize, PartialEq)]
pub struct Tuning {
pub enabled: bool,
@@ -19,8 +25,8 @@ type Tunings = HashMap<PlatformProfile, Tuning>;
pub struct Config {
// The current charge limit applied
pub charge_control_end_threshold: u8,
/// Save charge limit for restoring
#[serde(skip)]
/// Save charge limit for restoring after one-shot full charge
#[serde(default = "default_base_charge_limit")]
pub base_charge_control_end_threshold: u8,
pub disable_nvidia_powerd_on_battery: bool,
/// An optional command/script to run when power is changed to AC
@@ -86,6 +92,9 @@ impl Default for Config {
fn default() -> Self {
Self {
charge_control_end_threshold: 100,
// NOTE: This is intentionally 100 (not 0 like the serde default).
// New installs get 100 (no limit). Upgraded configs missing this
// field get 0 via serde, which skips restore_charge_limit().
base_charge_control_end_threshold: 100,
disable_nvidia_powerd_on_battery: true,
ac_command: Default::default(),

View File

@@ -11,6 +11,7 @@ ENV{DMI_FAMILY}=="*Zenbook*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*ProArt*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*TX Air*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*TX Gaming*", GOTO="asusd_start"
ENV{DMI_FAMILY}=="*EXPERTBOOK*", GOTO="asusd_start"
# No match so
GOTO="asusd_end"

78
distro-packaging/asusctl.spec Executable file → Normal file
View File

@@ -20,9 +20,9 @@
%global debug_package %{nil}
%endif
%define version 6.1.18
%define version 6.2.0
%define specrelease %{?dist}
%define pkg_release 9%{specrelease}
%define pkg_release 1%{specrelease}
# Use hardening ldflags.
%global rustflags -Clink-arg=-Wl,-z,relro,-z,now
@@ -31,7 +31,6 @@ Version: %{version}
Release: %{pkg_release}
Summary: Control fan speeds, LEDs, graphics modes, and charge levels for ASUS notebooks
License: MPLv2
Requires: power-profiles-daemon
Group: System Environment/Kernel
@@ -56,6 +55,7 @@ BuildRequires: pkgconfig(libseat)
BuildRequires: pkgconfig(libudev)
BuildRequires: pkgconfig(xkbcommon)
BuildRequires: pkgconfig(libzstd)
BuildRequires: pkgconfig(fontconfig)
BuildRequires: desktop-file-utils
%description
@@ -68,6 +68,7 @@ asus-nb-ctrl enables third-party apps to use the above with dbus methods.
%package rog-gui
Summary: An experimental GUI for %{name}
Requires: %{name} = %{version}-%{release}
%description rog-gui
A one-stop-shop GUI tool for asusd/asusctl. It aims to provide most controls,
@@ -75,11 +76,6 @@ a notification service, and ability to run in the background.
%prep
%autosetup
%if %{defined fedora}
%cargo_prep
sed -i 's|offline = true|offline = false|' .cargo/config.toml
sed -i 's|source.crates-io|source.ignore_this|' .cargo/config.toml
%else
mkdir -p .cargo
cat > .cargo/config.toml << 'EOF'
[term]
@@ -87,28 +83,69 @@ verbose = true
[net]
offline = false
EOF
%endif
%build
export RUSTFLAGS="%{rustflags}"
%if %{defined fedora}
%# Use an explicit cargo invocation for Fedora to avoid the macro adding `--locked`.
%# `--locked` breaks Fedora builds because the lockfile may not be appropriate for the distro buildroot.
/usr/bin/cargo auditable build --release
/usr/bin/cargo build --release --locked
%else
/usr/bin/cargo auditable build --release
/usr/bin/cargo auditable build --release --locked
%endif
%install
export RUSTFLAGS="%{rustflags}"
mkdir -p "%{buildroot}/%{_bindir}" "%{buildroot}%{_docdir}"
%make_install
install -D -m 0644 README.md %{buildroot}/%{_docdir}/%{name}/README.md
install -D -m 0644 rog-anime/README.md %{buildroot}/%{_docdir}/%{name}/README-anime.md
install -D -m 0644 rog-anime/data/diagonal-template.png %{buildroot}/%{_docdir}/%{name}/diagonal-template.png
%define _target_dir target/release
desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.desktop
# Install binaries
install -D -m 0755 %{_target_dir}/asusd %{buildroot}%{_bindir}/asusd
install -D -m 0755 %{_target_dir}/asusd-user %{buildroot}%{_bindir}/asusd-user
install -D -m 0755 %{_target_dir}/asusctl %{buildroot}%{_bindir}/asusctl
install -D -m 0755 %{_target_dir}/rog-control-center %{buildroot}%{_bindir}/rog-control-center
# Install systemd units
install -D -m 0644 data/asusd.service %{buildroot}%{_unitdir}/asusd.service
install -D -m 0644 data/asusd-user.service %{buildroot}%{_userunitdir}/asusd-user.service
# Install udev rules
install -D -m 0644 data/asusd.rules %{buildroot}%{_udevrulesdir}/99-asusd.rules
# Install dbus config
install -D -m 0644 data/asusd.conf %{buildroot}%{_datadir}/dbus-1/system.d/asusd.conf
# Install asusd data
install -D -m 0644 rog-aura/data/aura_support.ron %{buildroot}%{_datadir}/asusd/aura_support.ron
cp -r rog-anime/data/anime %{buildroot}%{_datadir}/asusd/
# Install rog-gui data
install -D -m 0644 rog-control-center/data/rog-control-center.desktop %{buildroot}%{_datadir}/applications/rog-control-center.desktop
install -D -m 0644 rog-control-center/data/rog-control-center.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/rog-control-center.png
mkdir -p %{buildroot}%{_datadir}/rog-gui/layouts
cp -r rog-aura/data/layouts/*.ron %{buildroot}%{_datadir}/rog-gui/layouts/
# Install icons
install -D -m 0644 data/icons/asus_notif_yellow.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_yellow.png
install -D -m 0644 data/icons/asus_notif_green.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_green.png
install -D -m 0644 data/icons/asus_notif_blue.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_blue.png
install -D -m 0644 data/icons/asus_notif_red.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_red.png
install -D -m 0644 data/icons/asus_notif_orange.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_orange.png
install -D -m 0644 data/icons/asus_notif_white.png %{buildroot}%{_datadir}/icons/hicolor/512x512/apps/asus_notif_white.png
install -D -m 0644 data/icons/scalable/gpu-compute.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-compute.svg
install -D -m 0644 data/icons/scalable/gpu-hybrid.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-hybrid.svg
install -D -m 0644 data/icons/scalable/gpu-integrated.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-integrated.svg
install -D -m 0644 data/icons/scalable/gpu-nvidia.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-nvidia.svg
install -D -m 0644 data/icons/scalable/gpu-vfio.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/gpu-vfio.svg
install -D -m 0644 data/icons/scalable/notification-reboot.svg %{buildroot}%{_datadir}/icons/hicolor/scalable/status/notification-reboot.svg
# Install docs
install -D -m 0644 README.md %{buildroot}%{_docdir}/%{name}/README.md
install -D -m 0644 rog-anime/README.md %{buildroot}%{_docdir}/%{name}/README-anime.md
install -D -m 0644 rog-anime/data/diagonal-template.png %{buildroot}%{_docdir}/%{name}/diagonal-template.png
# Install LICENSE to asusctl datadir
install -D -m 0644 LICENSE %{buildroot}%{_datadir}/asusctl/LICENSE
desktop-file-validate %{buildroot}%{_datadir}/applications/rog-control-center.desktop
%files
%license LICENSE
@@ -118,8 +155,6 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.d
%{_unitdir}/asusd.service
%{_userunitdir}/asusd-user.service
%{_udevrulesdir}/99-asusd.rules
#%dir %{_sysconfdir}/asusd/
%{_datadir}/asusd/aura_support.ron
%{_datadir}/dbus-1/system.d/asusd.conf
%{_datadir}/icons/hicolor/512x512/apps/asus_notif_yellow.png
%{_datadir}/icons/hicolor/512x512/apps/asus_notif_green.png
@@ -134,6 +169,7 @@ desktop-file-validate %{buildroot}/%{_datadir}/applications/rog-control-center.d
%{_datadir}/icons/hicolor/scalable/status/gpu-vfio.svg
%{_datadir}/icons/hicolor/scalable/status/notification-reboot.svg
%{_docdir}/%{name}/
%{_datadir}/asusctl/
%{_datadir}/asusd/
%files rog-gui

View File

@@ -63,6 +63,8 @@ pub enum AnimeType {
GA401,
GA402,
GU604,
G635L,
G835LW,
#[default]
Unsupported,
}
@@ -71,10 +73,12 @@ impl FromStr for AnimeType {
type Err = AnimeError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(match s {
"ga401" | "GA401" => Self::GA401,
"ga402" | "GA402" => Self::GA402,
"gu604" | "GU604" => Self::GU604,
Ok(match s.to_uppercase().as_str() {
"GA401" => Self::GA401,
"GA402" => Self::GA402,
"GU604" => Self::GU604,
"G635L" => Self::G635L,
"G835LW" => Self::G835LW,
_ => Self::Unsupported,
})
}
@@ -89,6 +93,8 @@ impl AnimeType {
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604
} else if board_name.contains("G635L") || board_name.contains("G635L") {
AnimeType::G635L
} else {
AnimeType::Unsupported
}
@@ -98,6 +104,7 @@ impl AnimeType {
pub fn width(&self) -> usize {
match self {
AnimeType::GU604 => 70,
AnimeType::G835LW => 74,
_ => 74,
}
}
@@ -107,6 +114,7 @@ impl AnimeType {
match self {
AnimeType::GA401 => 36,
AnimeType::GU604 => 43,
AnimeType::G835LW => 39,
_ => 39,
}
}
@@ -116,6 +124,7 @@ impl AnimeType {
match self {
AnimeType::GA401 => PANE_LEN * 2,
AnimeType::GU604 => PANE_LEN * 3,
AnimeType::G835LW => PANE_LEN * 3,
_ => PANE_LEN * 3,
}
}
@@ -180,7 +189,13 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
let mut buffers = match anime.anime {
AnimeType::GA401 => vec![[0; 640]; 2],
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported => vec![[0; 640]; 3],
AnimeType::GA402
| AnimeType::GU604
| AnimeType::G635L
| AnimeType::G835LW
| AnimeType::Unsupported => {
vec![[0; 640]; 3]
}
};
for (idx, chunk) in anime.data.as_slice().chunks(PANE_LEN).enumerate() {
@@ -191,7 +206,11 @@ impl TryFrom<AnimeDataBuffer> for AnimePacketType {
if matches!(
anime.anime,
AnimeType::GA402 | AnimeType::GU604 | AnimeType::Unsupported
AnimeType::GA402
| AnimeType::GU604
| AnimeType::G635L
| AnimeType::G835LW
| AnimeType::Unsupported
) {
buffers[2][..7].copy_from_slice(&USB_PREFIX3);
}

View File

@@ -243,7 +243,7 @@ impl From<AnimShutdown> for i32 {
#[inline]
pub fn get_anime_type() -> AnimeType {
let dmi = DMIID::new().unwrap_or_default();
let board_name = dmi.board_name;
let board_name = dmi.board_name.to_uppercase();
if board_name.contains("GA401I") || board_name.contains("GA401Q") {
AnimeType::GA401
@@ -251,6 +251,8 @@ pub fn get_anime_type() -> AnimeType {
AnimeType::GA402
} else if board_name.contains("GU604V") {
AnimeType::GU604
} else if board_name.contains("G635L") {
AnimeType::G635L
} else {
AnimeType::Unsupported
}

View File

@@ -107,6 +107,15 @@
advanced_type: r#None,
power_zones: [Keyboard],
),
(
device_name: "FX607V",
product_id: "",
layout_name: "fa506i",
basic_modes: [Static, Breathe, RainbowCycle, Pulse],
basic_zones: [],
advanced_type: Zoned([SingleZone]),
power_zones: [Keyboard],
),
(
device_name: "FX617X",
product_id: "",
@@ -305,6 +314,15 @@
advanced_type: PerKey,
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: "G712LI",
product_id: "",
@@ -503,6 +521,15 @@
advanced_type: PerKey,
power_zones: [Keyboard, Lightbar],
),
(
device_name: "G815L",
product_id: "",
layout_name: "g814ji-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],
),
(
device_name: "G834J",
product_id: "",

View File

@@ -0,0 +1,375 @@
(
locale: "US",
key_shapes: {
"regular": Led(
width: 1.0,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"regular_spacing": Blank(
width: 1.2,
height: 0.0,
),
"rog_row": Led(
width: 1.0,
height: 0.7,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.6,
),
"rog_row_blocking": Blank(
width: 1.2,
height: 0.0,
),
"func_space": Blank(
width: 0.6,
height: 0.0,
),
"backspace": Led(
width: 2.2,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"tab": Led(
width: 1.6,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"backslash": Led(
width: 1.6,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"capsplonk": Led(
width: 2.0,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"return": Led(
width: 2.4,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"lshift": Led(
width: 2.6,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"rshift": Led(
width: 3.0,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"lctrl": Led(
width: 1.4,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"spacebar": Led(
width: 5.8,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"rctrl": Led(
width: 1.2,
height: 1.0,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"up_arrow": Led(
width: 0.8,
height: 0.8,
pad_left: 1.1,
pad_right: 1.1,
pad_top: 0.1,
pad_bottom: 0.1,
),
"arrows_spacer": Blank(
width: 15.0,
height: 0.0,
),
"arrows": Led(
width: 0.8,
height: 0.8,
pad_left: 0.1,
pad_right: 0.1,
pad_top: -0.1,
pad_bottom: 0.1,
),
"row_end_spacing": Blank(
width: 0.4,
height: 0.0,
),
"lid_logo": Led(
width: 2.6,
height: 1.2,
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_left": Led(
width: 0.6,
height: 3.6,
pad_left: -1.2,
pad_right: 0.2,
pad_top: -3.0,
pad_bottom: 0.3,
),
"lightbar_corner_left": Led(
width: 0.8,
height: 0.6,
pad_left: -0.6,
pad_right: 0.2,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_bottom": Led(
width: 12.6,
height: 0.5,
pad_left: -0.1,
pad_right: -0.1,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_corner_right": Led(
width: 0.8,
height: 0.6,
pad_left: 0.0,
pad_right: 0.2,
pad_top: 0.8,
pad_bottom: 0.0,
),
"lightbar_right": Led(
width: 0.6,
height: 3.6,
pad_left: -0.8,
pad_right: 0.2,
pad_top: -3.0,
pad_bottom: 0.3,
),
},
key_rows: [
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Blocking, "rog_row_blocking"),
(Blocking, "rog_row_blocking"),
(VolDown, "rog_row"),
(VolUp, "rog_row"),
(MicMute, "rog_row"),
(RogFan, "rog_row"),
(RogApp, "rog_row"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Esc, "regular"),
(Spacing, "regular_spacing"),
(F1, "regular"),
(F2, "regular"),
(F3, "regular"),
(F4, "regular"),
(Spacing, "func_space"),
(F5, "regular"),
(F6, "regular"),
(F7, "regular"),
(F8, "regular"),
(Spacing, "func_space"),
(F9, "regular"),
(F10, "regular"),
(F11, "regular"),
(F12, "regular"),
(Spacing, "row_end_spacing"),
(Del, "regular"), // Should be super/insert
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Tilde, "regular"),
(N1, "regular"),
(N2, "regular"),
(N3, "regular"),
(N4, "regular"),
(N5, "regular"),
(N6, "regular"),
(N7, "regular"),
(N8, "regular"),
(N9, "regular"),
(N0, "regular"),
(Hyphen, "regular"),
(Equals, "regular"),
(Backspace, "backspace"),
(Spacing, "row_end_spacing"),
(MediaPlay, "regular"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Tab, "tab"),
(Q, "regular"),
(W, "regular"),
(E, "regular"),
(R, "regular"),
(T, "regular"),
(Y, "regular"),
(U, "regular"),
(I, "regular"),
(O, "regular"),
(P, "regular"),
(LBracket, "regular"),
(RBracket, "regular"),
(BackSlash, "backslash"),
(Spacing, "row_end_spacing"),
(MediaStop, "regular"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Caps, "capsplonk"),
(A, "regular"),
(S, "regular"),
(D, "regular"),
(F, "regular"),
(G, "regular"),
(H, "regular"),
(J, "regular"),
(K, "regular"),
(L, "regular"),
(SemiColon, "regular"),
(Quote, "regular"),
(Return, "return"),
(Spacing, "row_end_spacing"),
(MediaNext, "regular"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(LShift, "lshift"),
(Z, "regular"),
(X, "regular"),
(C, "regular"),
(V, "regular"),
(B, "regular"),
(N, "regular"),
(M, "regular"),
(Comma, "regular"),
(Period, "regular"),
(FwdSlash, "regular"),
(Rshift, "rshift"),
(Spacing, "row_end_spacing"),
(MediaPrev, "regular"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(LCtrl, "lctrl"),
(LFn, "regular"),
(Meta, "regular"),
(LAlt, "regular"),
(Spacebar, "spacebar"),
(RAlt, "regular"),
(PrtSc, "regular"),
(RCtrl, "rctrl"),
(Up, "up_arrow"),
(Spacing, "row_end_spacing"),
(PrtSc, "regular"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(Spacing, "arrows_spacer"),
(Left, "arrows"),
(Down, "arrows"),
(Right, "arrows"),
],
),
(
pad_left: 6.5,
pad_right: 6.5,
pad_top: 0.2,
pad_bottom: 0.1,
row: [
(LidLogo, "lid_logo"),
],
),
(
pad_left: 0.1,
pad_right: 0.1,
pad_top: 0.1,
pad_bottom: 0.1,
row: [
(LightbarLeft, "lightbar_left"),
(LightbarLeftCorner, "lightbar_corner_left"),
(LightbarLeftBottom, "lightbar_bottom"),
(LightbarRightBottom, "lightbar_bottom"),
(LightbarRightCorner, "lightbar_corner_right"),
(LightbarRight, "lightbar_right"),
],
),
],
)

View File

@@ -164,6 +164,25 @@ impl LedSupportFile {
return Some(data);
}
// If the system-wide files were not found (typical in CI or
// development environments), attempt to load the bundled
// `data/aura_support.ron` from the crate so tests and local runs
// behave the same as when the package is installed.
// Attempt to load a bundled `aura_support.ron` included at compile time.
// Using `include_str!` ensures the data is available regardless of
// runtime `CARGO_MANIFEST_DIR` or CI environment differences.
let bundled_buf = include_str!("../data/aura_support.ron");
if !bundled_buf.is_empty() {
if let Ok(tmp) = ron::from_str::<LedSupportFile>(bundled_buf) {
data.0.append(&mut tmp.0.clone());
data.0.sort_by(|a, b| a.device_name.cmp(&b.device_name));
info!("Loaded bundled LED support data (embedded)");
return Some(data);
} else {
warn!("Could not parse embedded bundled data file");
}
}
warn!("Does {} exist?", ASUS_LED_MODE_USER_CONF);
None
}

View File

@@ -24,11 +24,16 @@ use tokio::runtime::Runtime;
#[tokio::main]
async fn main() -> Result<()> {
// Ensure tracing spans are quiet by default unless user overrides
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "warn,tracing=error,zbus=error");
}
let mut logger = env_logger::Builder::new();
logger
.filter_level(LevelFilter::Warn)
.parse_default_env()
.target(env_logger::Target::Stdout)
.filter_level(LevelFilter::Info)
.parse_default_env()
.target(env_logger::Target::Stderr)
.format_timestamp(None)
.init();

View File

@@ -89,7 +89,7 @@ where
}
}
if paths.len() > 1 {
println!("Multiple asusd interfaces devices found");
log::warn!("Multiple asusd interfaces devices found");
}
if !paths.is_empty() {
let mut ctrl = Vec::new();
@@ -129,7 +129,7 @@ where
}
}
if paths.len() > 1 {
println!("Multiple asusd interfaces devices found");
log::warn!("Multiple asusd interfaces devices found");
}
if !paths.is_empty() {
let mut ctrl = Vec::new();

View File

@@ -383,7 +383,7 @@ impl From<&str> for FirmwareAttribute {
"nv_dynamic_boost" => Self::NvDynamicBoost,
"nv_temp_target" => Self::NvTempTarget,
"nv_base_tgp" => Self::DgpuBaseTgp,
"dgpu_tgp" => Self::DgpuTgp,
"nv_tgp" => Self::DgpuTgp,
"charge_mode" => Self::ChargeMode,
"boot_sound" => Self::BootSound,
"mcu_powersave" => Self::McuPowersave,
@@ -420,7 +420,7 @@ impl From<FirmwareAttribute> for &str {
FirmwareAttribute::NvDynamicBoost => "nv_dynamic_boost",
FirmwareAttribute::NvTempTarget => "nv_temp_target",
FirmwareAttribute::DgpuBaseTgp => "dgpu_base_tgp",
FirmwareAttribute::DgpuTgp => "dgpu_tgp",
FirmwareAttribute::DgpuTgp => "nv_tgp",
FirmwareAttribute::ChargeMode => "charge_mode",
FirmwareAttribute::BootSound => "boot_sound",
FirmwareAttribute::McuPowersave => "mcu_powersave",

View File

@@ -13,8 +13,11 @@ use crate::usb::{PROD_ID1, PROD_ID1_STR, PROD_ID2, PROD_ID2_STR};
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub enum SlashType {
GA403,
GA403W,
GA605,
GU605,
GU605C,
G614F,
#[default]
Unsupported,
}
@@ -22,28 +25,40 @@ pub enum SlashType {
impl SlashType {
pub const fn prod_id(&self) -> u16 {
match self {
SlashType::GA403W => PROD_ID2,
SlashType::GA403 => PROD_ID1,
SlashType::GA605 => PROD_ID2,
SlashType::GU605 => PROD_ID1,
SlashType::GU605C => PROD_ID2,
SlashType::G614F => PROD_ID2,
SlashType::Unsupported => 0,
}
}
pub const fn prod_id_str(&self) -> &str {
match self {
SlashType::GA403W => PROD_ID2_STR,
SlashType::GA403 => PROD_ID1_STR,
SlashType::GA605 => PROD_ID2_STR,
SlashType::GU605 => PROD_ID1_STR,
SlashType::GU605C => PROD_ID2_STR,
SlashType::G614F => PROD_ID2_STR,
SlashType::Unsupported => "",
}
}
pub fn from_dmi() -> Self {
let board_name = DMIID::new().unwrap_or_default().board_name.to_uppercase();
if board_name.contains("GA403") {
if board_name.contains("G614F") {
SlashType::G614F
} else if board_name.contains("GA403W") {
SlashType::GA403W
} else if board_name.contains("GA403") {
SlashType::GA403
} else if board_name.contains("GA605") {
SlashType::GA605
} else if board_name.contains("GU605C") {
SlashType::GU605C
} else if board_name.contains("GU605") {
SlashType::GU605
} else {
@@ -56,10 +71,13 @@ impl FromStr for SlashType {
type Err = SlashError;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Ok(match s {
"ga403" | "GA403" => Self::GA403,
"ga605" | "GA605" => Self::GA605,
"gu605" | "GU605" => Self::GU605,
Ok(match s.to_uppercase().as_str() {
"GA403W" => Self::GA403W,
"GA403" => Self::GA403,
"GA605" => Self::GA605,
"GU605C" => Self::GU605C,
"GU605" => Self::GU605,
"G614FR" => Self::G614F,
_ => Self::Unsupported,
})
}

View File

@@ -37,12 +37,17 @@ pub fn get_slash_type() -> SlashType {
let dmi = DMIID::new()
.map_err(|_| SlashError::NoDevice)
.unwrap_or_default();
let board_name = dmi.board_name;
if board_name.contains("GA403") {
let board_name = dmi.board_name.to_uppercase();
if board_name.contains("G614F") {
SlashType::G614F
} else if board_name.contains("GA403W") {
SlashType::GA403W
} else if board_name.contains("GA403") {
SlashType::GA403
} else if board_name.contains("GA605") {
SlashType::GA605
} else if board_name.contains("GU605C") {
SlashType::GU605C
} else if board_name.contains("GU605") {
SlashType::GU605
} else {
@@ -52,9 +57,12 @@ pub fn get_slash_type() -> SlashType {
pub const fn report_id(slash_type: SlashType) -> u8 {
match slash_type {
SlashType::GA403W => REPORT_ID_19B6,
SlashType::GA403 => REPORT_ID_193B,
SlashType::GA605 => REPORT_ID_19B6,
SlashType::G614F => REPORT_ID_19B6,
SlashType::GU605 => REPORT_ID_193B,
SlashType::GU605C => REPORT_ID_19B6,
SlashType::Unsupported => REPORT_ID_19B6,
}
}

View File

@@ -43,10 +43,12 @@ impl AniMatrix {
vertical: 2,
horizontal: 5,
},
AnimeType::GA402 | AnimeType::Unsupported => LedShape {
vertical: 2,
horizontal: 5,
},
AnimeType::GA402 | AnimeType::G635L | AnimeType::G835LW | AnimeType::Unsupported => {
LedShape {
vertical: 2,
horizontal: 5,
}
}
AnimeType::GU604 => LedShape {
vertical: 2,
horizontal: 5,
@@ -56,7 +58,9 @@ impl AniMatrix {
// Do a hard mapping of each (derived from wireshardk captures)
let rows = match model {
AnimeType::GA401 => GA401.to_vec(),
AnimeType::GA402 | AnimeType::Unsupported => GA402.to_vec(),
AnimeType::GA402 | AnimeType::G635L | AnimeType::G835LW | AnimeType::Unsupported => {
GA402.to_vec()
}
AnimeType::GU604 => GU604.to_vec(),
};