Compare commits

..

16 Commits

Author SHA1 Message Date
Luke D Jones de3b803f14 Add DBUS methods to toggle next/previous aura mode 2020-10-25 15:49:14 +13:00
Luke D Jones 0558f919c4 Add DBUS method to toggle to next profile 2020-10-25 15:02:35 +13:00
Luke Jones 68ea73c847 Merge branch 'asere/anime_on_off' into 'next'
AniMe: adding --on and --off options to turn on/off (and accept/reject write requests)

See merge request asus-linux/asus-nb-ctrl!11
2020-10-25 01:14:12 +00:00
Luke Jones 96ddb7132d Merge branch 'asere/show_keyboard_brightness' into 'next'
Improving user experience by showing current keyboard led brightness

See merge request asus-linux/asus-nb-ctrl!10
2020-10-25 01:12:21 +00:00
Asere d36ac44603 updating option "-k" to show current brightness: asusctl -k 2020-10-23 02:00:08 +02:00
Asere 5d06c87943 AniMe: adding --on and --off options to turn on/off (and accept/reject write requests) 2020-10-22 14:09:05 +02:00
Luke D Jones 588e3c0102 Panic if config file is bad 2020-10-22 08:28:12 +13:00
Luke D Jones 6ce32c1cab Fix one super silly bug
closes #30
2020-10-22 08:16:00 +13:00
Luke Jones a23c51e5db Adding Anime commands to asusctl 2020-10-11 22:46:06 +00:00
Asere 3845071ba3 adding Anime feature: led brightness command to asusctl, and updating dbus client 2020-10-12 00:11:26 +02:00
Luke Jones a48b3634bf Merge branch 'next' into 'next'
Add some basic zsh completions for asusctl

See merge request asus-linux/asus-nb-ctrl!8
2020-10-05 00:38:34 +00:00
Luke Jones 806882b2e9 Merge branch 'next' into 'next'
fixed fan presets for profiles

See merge request asus-linux/asus-nb-ctrl!7
2020-10-05 00:37:43 +00:00
Luke D Jones 9ac3c46fe6 Actually enable/disable gfx switch control 2020-10-05 09:32:46 +13:00
Luke D Jones 6817a1c027 Bump dbus autogen 2020-10-05 09:31:07 +13:00
Dylan Jones cf2be1b12b Add some basic zsh completions for asusctl 2020-09-30 13:28:05 -04:00
Cuong a7f6e8bd24 fixed fan presets for profiles 2020-09-28 10:04:57 +00:00
25 changed files with 552 additions and 100 deletions
+10
View File
@@ -5,6 +5,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
# [2.1.0] - 2020-10-25
### Added
- Option to turn off AniMe display (@asere)
### Changed
- Change option -k to show current LED bright (@asere)
- Correctly disable GFX control via config
- Panic and exit if config can't be parsed
- Add DBUS method to toggle to next fan/thermal profile
- Add DBUS method to toggle to next/prev Aura mode
# [2.0.5] - 2020-09-29
### Changed
- Bugfixes
Generated
+3 -3
View File
@@ -29,7 +29,7 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
[[package]]
name = "asus-nb"
version = "2.0.4"
version = "2.1.0"
dependencies = [
"ctrl-gfx",
"dbus",
@@ -46,7 +46,7 @@ dependencies = [
[[package]]
name = "asus-nb-ctrl"
version = "2.0.4"
version = "2.1.0"
dependencies = [
"asus-nb",
"ctrl-gfx",
@@ -191,7 +191,7 @@ dependencies = [
[[package]]
name = "ctrl-gfx"
version = "2.1.1"
version = "2.1.3"
dependencies = [
"log",
"sysfs-class",
+2
View File
@@ -52,6 +52,7 @@ install: all
install -D -m 0644 "data/icons/asus_notif_yellow.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_yellow.png"
install -D -m 0644 "data/icons/asus_notif_green.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_green.png"
install -D -m 0644 "data/icons/asus_notif_red.png" "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_red.png"
install -D -m 0644 "data/_asusctl" "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
uninstall:
rm -f "$(DESTDIR)$(bindir)/$(BIN_C)"
@@ -64,6 +65,7 @@ uninstall:
rm -f "$(DESTDIR)/lib/systemd/system/$(BIN_D).service"
rm -r "$(DESTDIR)/lib/systemd/user/$(BIN_N).service"
rm -r "$(DESTDIR)/usr/share/icons/hicolor/512x512/apps/asus_notif_*"
rm -f "$(DESTDIR)/usr/share/zsh/site-functions/_asusctl"
update:
cargo update
+14
View File
@@ -117,6 +117,20 @@ If you model isn't getting the correct led modes, you can edit the file
use `cat /sys/class/dmi/id/product_name` to get details about your laptop.
# Keybinds
To switch to next/previous Aura modes you will need to bind both the aura keys (if available) to one of:
**Next**
```
asusctl led-mode -n
```
**Previous**
```
asusctl led-mode -p
```
To switch Fan/Thermal profiles you need to bind the Fn+F5 key to `asusctl profile -n`.
# BUILDING
Requirements are:
+6
View File
@@ -76,6 +76,12 @@ Accepts an integer from the following:
- `1`: Boost mode
- `2`: Silent mode
## dbus-send examples:
```
dbus-send --system --type=method_call --dest=org.asuslinux.Daemon /org/asuslinux/Profile org.asuslinux.Daemon.NextProfile
```
## dbus-send examples OUTDATED
```
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "asus-nb-ctrl"
version = "2.0.5"
version = "2.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+10 -7
View File
@@ -30,18 +30,18 @@ impl Config {
.write(true)
.create(true)
.open(&CONFIG_PATH)
.expect(&format!("The file {} or directory /etc/asusd/ is missing", CONFIG_PATH)); // okay to cause panic here
.expect(&format!(
"The file {} or directory /etc/asusd/ is missing",
CONFIG_PATH
)); // okay to cause panic here
let mut buf = String::new();
if let Ok(l) = file.read_to_string(&mut buf) {
if l == 0 {
self = Config::create_default(&mut file, &supported_led_modes);
} else {
self = serde_json::from_str(&buf).unwrap_or_else(|_| {
warn!(
"Could not deserialise {}. Overwriting with default",
CONFIG_PATH
);
Config::create_default(&mut file, &supported_led_modes)
warn!("Could not deserialise {}", CONFIG_PATH);
panic!("Please remove {} then restart asusd", CONFIG_PATH);
});
}
}
@@ -61,11 +61,14 @@ impl Config {
config.kbd_backlight_modes.push(AuraModes::from(*n))
}
let profile = Profile::default();
let mut profile = Profile::default();
profile.fan_preset = 0;
profile.turbo = true;
config.power_profiles.insert("normal".into(), profile);
let mut profile = Profile::default();
profile.fan_preset = 1;
profile.turbo = true;
config.power_profiles.insert("boost".into(), profile);
let mut profile = Profile::default();
+30 -2
View File
@@ -9,6 +9,10 @@ const INIT: u8 = 0xc2;
const APPLY: u8 = 0xc3;
const SET: u8 = 0xc4;
// Used to turn the panel on and off
// The next byte can be 0x03 for "on" and 0x00 for "off"
const ON_OFF : u8 = 0x04;
use asus_nb::error::AuraError;
use log::{error, info, warn};
use rusb::{Device, DeviceHandle};
@@ -22,6 +26,7 @@ use zbus::dbus_interface;
pub enum AnimatrixCommand {
Apply,
Set,
Write(Vec<u8>),
WriteImage(Vec<Vec<u8>>),
//ReloadLast,
}
@@ -34,6 +39,8 @@ pub struct CtrlAnimeDisplay {
//AnimatrixWrite
pub trait Dbus {
fn set_anime(&mut self, input: Vec<Vec<u8>>);
fn set_on_off(&mut self, status: bool);
}
impl crate::ZbusAdd for CtrlAnimeDisplay {
@@ -54,6 +61,26 @@ impl Dbus for CtrlAnimeDisplay {
self.do_command(AnimatrixCommand::WriteImage(input))
.unwrap_or_else(|err| warn!("{}", err));
}
fn set_on_off(&mut self, status: bool) {
let mut activity : Vec<u8> = vec![0; PACKET_SIZE];
activity[0] = DEV_PAGE;
activity[1] = WRITE;
activity[2] = ON_OFF;
let status_str;
if status {
activity[3] = 0x03;
status_str = "on";
} else {
activity[3] = 0x00;
status_str = "off";
}
info!("Turning {} the AniMe", status_str);
self.do_command(AnimatrixCommand::Write(activity))
.unwrap_or_else(|err| warn!("{}", err));
}
}
impl CtrlAnimeDisplay {
@@ -99,9 +126,10 @@ impl CtrlAnimeDisplay {
}
match command {
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
AnimatrixCommand::Set => self.do_set()?,
AnimatrixCommand::Apply => self.do_apply()?,
AnimatrixCommand::Set => self.do_set()?,
AnimatrixCommand::Write(bytes) => self.write_bytes(&bytes)?,
AnimatrixCommand::WriteImage(effect) => self.write_image(effect)?,
//AnimatrixCommand::ReloadLast => self.reload_last_builtin(&config).await?,
}
Ok(())
+22 -2
View File
@@ -31,6 +31,7 @@ impl DbusFanAndCpu {
#[dbus_interface(name = "org.asuslinux.Daemon")]
impl DbusFanAndCpu {
/// Set profile details
fn set_profile(&self, profile: String) {
if let Ok(event) = serde_json::from_str(&profile) {
if let Ok(mut ctrl) = self.inner.try_lock() {
@@ -45,6 +46,23 @@ impl DbusFanAndCpu {
}
}
/// Fetch the active profile name
fn next_profile(&mut self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.do_next_profile(&mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
if let Some(profile) = cfg.power_profiles.get(&cfg.active_profile) {
if let Ok(json) = serde_json::to_string(profile) {
self.notify_profile(&json)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
}
}
/// Fetch the active profile name
fn active_profile_name(&mut self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
@@ -55,6 +73,7 @@ impl DbusFanAndCpu {
"Failed".to_string()
}
/// Fetch the active profile details
fn profile(&mut self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.try_lock() {
@@ -178,7 +197,8 @@ impl CtrlFanAndCPU {
}
}
pub(super) fn do_update(&mut self, config: &mut Config) -> Result<(), RogError> {
/// Toggle to next profile in list
pub(super) fn do_next_profile(&mut self, config: &mut Config) -> Result<(), RogError> {
config.read();
let mut i = config
@@ -232,7 +252,7 @@ impl CtrlFanAndCPU {
config: &mut Config,
) -> Result<(), RogError> {
match event {
ProfileEvent::Toggle => self.do_update(config)?,
ProfileEvent::Toggle => self.do_next_profile(config)?,
ProfileEvent::ChangeMode(mode) => {
self.set_fan_mode(*mode, config)?;
}
+70 -5
View File
@@ -72,6 +72,25 @@ impl DbusKbdBacklight {
}
}
fn next_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(false, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
fn prev_led_mode(&self) {
if let Ok(mut ctrl) = self.inner.try_lock() {
if let Ok(mut cfg) = ctrl.config.clone().try_lock() {
ctrl.toggle_mode(true, &mut cfg)
.unwrap_or_else(|err| warn!("{}", err));
}
}
}
/// Return the current mode data
fn led_mode(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
@@ -86,6 +105,7 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string()
}
/// Return a list of available modes
fn led_modes(&self) -> String {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
@@ -98,6 +118,17 @@ impl DbusKbdBacklight {
"SetKeyBacklight could not deserialise".to_string()
}
/// Return the current LED brightness
fn led_brightness(&self) -> i8 {
if let Ok(ctrl) = self.inner.try_lock() {
if let Ok(cfg) = ctrl.config.clone().try_lock() {
return cfg.kbd_led_brightness as i8;
}
}
warn!("SetKeyBacklight could not deserialise");
-1
}
#[dbus_interface(signal)]
fn notify_led(&self, data: &str) -> zbus::Result<()>;
}
@@ -152,11 +183,11 @@ impl crate::CtrlTask for CtrlKbdBacklight {
let mut file = OpenOptions::new()
.read(true)
.open(&self.bright_node)
.map_err(|err| {
match err.kind() {
std::io::ErrorKind::NotFound => RogError::MissingLedBrightNode((&self.bright_node).into(), err),
_ => RogError::Path((&self.bright_node).into(), err),
.map_err(|err| match err.kind() {
std::io::ErrorKind::NotFound => {
RogError::MissingLedBrightNode((&self.bright_node).into(), err)
}
_ => RogError::Path((&self.bright_node).into(), err),
})?;
let mut buf = [0u8; 1];
file.read_exact(&mut buf)
@@ -311,7 +342,9 @@ impl CtrlKbdBacklight {
fn write_bytes(&self, message: &[u8]) -> Result<(), RogError> {
if let Some(led_node) = &self.led_node {
if let Ok(mut file) = OpenOptions::new().write(true).open(led_node) {
return file.write_all(message).map_err(|err| RogError::Write("write_bytes".into(), err));
return file
.write_all(message)
.map_err(|err| RogError::Write("write_bytes".into(), err));
}
}
Err(RogError::NotSupported)
@@ -367,6 +400,38 @@ impl CtrlKbdBacklight {
Ok(())
}
#[inline]
fn toggle_mode(&mut self, reverse: bool, config: &mut Config) -> Result<(), RogError> {
let current = config.kbd_backlight_mode;
if let Some(idx) = self.supported_modes.iter().position(|v| *v == current) {
let mut idx = idx;
// goes past end of array
if reverse {
if idx == 0 {
idx = self.supported_modes.len() - 1;
} else {
idx -= 1;
}
} else {
idx += 1;
if idx == self.supported_modes.len() {
idx = 0;
}
}
let next = self.supported_modes[idx];
config.read();
if let Some(data) = config.get_led_mode_data(next) {
self.write_mode(&data)?;
config.kbd_backlight_mode = next;
}
config.write();
}
Ok(())
}
#[inline]
fn write_mode(&mut self, mode: &AuraModes) -> Result<(), RogError> {
match mode {
+19 -15
View File
@@ -15,10 +15,10 @@ use std::io::Write;
use std::sync::Arc;
use std::sync::Mutex;
use zbus::fdo;
use zbus::Connection;
use std::convert::Into;
use std::convert::TryInto;
use zbus::fdo;
use zbus::Connection;
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
@@ -55,6 +55,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
.request_name(DBUS_NAME, fdo::RequestNameFlags::ReplaceExisting.into())?;
let mut object_server = zbus::ObjectServer::new(&connection);
let enable_gfx_switching = config.gfx_managed;
let config = Arc::new(Mutex::new(config));
match CtrlCharge::new(config.clone()) {
@@ -79,14 +80,16 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
}
}
match CtrlGraphics::new() {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
if enable_gfx_switching {
match CtrlGraphics::new() {
Ok(mut ctrl) => {
ctrl.reload()
.unwrap_or_else(|err| warn!("Gfx controller: {}", err));
ctrl.add_to_server(&mut object_server);
}
Err(err) => {
error!("Gfx control: {}", err);
}
}
}
@@ -128,10 +131,11 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
for ctrl in tasks.iter() {
if let Ok(mut lock) = ctrl.try_lock() {
lock.do_task().map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
lock.do_task()
.map_err(|err| {
warn!("do_task error: {}", err);
})
.ok();
}
}
});
@@ -140,7 +144,7 @@ fn start_daemon() -> Result<(), Box<dyn Error>> {
let x = obj.limit();
obj.notify_charge(x as u8)
})?;
loop {
if let Err(err) = object_server.try_handle_next() {
eprintln!("{}", err);
+87 -11
View File
@@ -1,20 +1,20 @@
use asus_nb::{
cli_options::{LedBrightness, SetAuraBuiltin},
anime_dbus::AniMeDbusWriter,
cli_options::{AniMeActions, LedBrightness, SetAuraBuiltin},
core_dbus::AuraDbusClient,
profile::{ProfileCommand, ProfileEvent},
};
use ctrl_gfx::vendors::GfxVendors;
use daemon::ctrl_fan_cpu::FanLevel;
use gumdrop::Options;
use gumdrop::{Opt, Options};
use log::LevelFilter;
use std::io::Write;
use std::process::Command;
use std::{env::args, io::Write, process::Command};
use yansi_term::Colour::Green;
use yansi_term::Colour::Red;
#[derive(Options)]
#[derive(Default, Options)]
struct CLIStart {
#[options(help = "print help message")]
#[options(help_flag, help = "print help message")]
help: bool,
#[options(help = "show program version number")]
version: bool,
@@ -36,13 +36,19 @@ enum CliCommand {
Profile(ProfileCommand),
#[options(help = "Set the graphics mode")]
Graphics(GraphicsCommand),
#[options(name = "anime", help = "Manage AniMe Matrix")]
AniMe(AniMeCommand),
}
#[derive(Options)]
struct LedModeCommand {
#[options(help = "print help message")]
help: bool,
#[options(command, required)]
#[options(help = "switch to next aura mode")]
next_mode: bool,
#[options(help = "switch to previous aura mode")]
prev_mode: bool,
#[options(command)]
command: Option<SetAuraBuiltin>,
}
@@ -60,6 +66,18 @@ struct GraphicsCommand {
force: bool,
}
#[derive(Options)]
struct AniMeCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "turn on the panel (and accept write requests)", no_short)]
on: bool,
#[options(help = "turn off the panel (and reject write requests)", no_short)]
off: bool,
#[options(command)]
command: Option<AniMeActions>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut logger = env_logger::Builder::new();
logger
@@ -68,30 +86,88 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.filter(None, LevelFilter::Info)
.init();
let parsed = CLIStart::parse_args_default_or_exit();
let mut args: Vec<String> = args().collect();
args.remove(0);
let parsed: CLIStart;
let missing_argument_k = gumdrop::Error::missing_argument(Opt::Short('k'));
match CLIStart::parse_args_default(&args) {
Ok(p) => {
parsed = p;
}
Err(err) if err.to_string() == missing_argument_k.to_string() => {
parsed = CLIStart {
kbd_bright: Some(LedBrightness::new(None)),
..Default::default()
};
}
Err(err) => {
eprintln!("source {:?}", err);
std::process::exit(2);
}
}
if parsed.help_requested() {
// As help option don't work with `parse_args_default`
// we will call `parse_args_default_or_exit` instead
CLIStart::parse_args_default_or_exit();
}
if parsed.version {
println!("Version: {}", daemon::VERSION);
}
let writer = AuraDbusClient::new()?;
let anime_writer = AniMeDbusWriter::new()?;
match parsed.command {
Some(CliCommand::LedMode(mode)) => {
if let Some(command) = mode.command {
if mode.next_mode && mode.prev_mode {
println!("Please specify either next or previous")
}
if mode.next_mode {
writer.next_keyboard_led_mode()?;
} else if mode.prev_mode {
writer.prev_keyboard_led_mode()?;
} else if let Some(command) = mode.command {
writer.write_builtin_mode(&command.into())?
}
}
Some(CliCommand::Profile(command)) => {
writer.write_profile_command(&ProfileEvent::Cli(command))?
if command.next {
writer.next_fan_profile()?;
} else {
writer.write_profile_command(&ProfileEvent::Cli(command))?
}
}
Some(CliCommand::Graphics(command)) => do_gfx(command, &writer)?,
Some(CliCommand::AniMe(anime)) => {
if anime.on {
anime_writer.turn_on()?;
} else if anime.off {
anime_writer.turn_off()?;
} else if let Some(action) = anime.command {
match action {
AniMeActions::Leds(anime_leds) => {
let led_brightness = anime_leds.led_brightness();
anime_writer.set_leds_brightness(led_brightness)?;
}
}
}
}
None => (),
}
if let Some(brightness) = parsed.kbd_bright {
writer.write_brightness(brightness.level())?;
match brightness.level() {
None => {
let level = writer.get_led_brightness()?;
println!("Current keyboard led brightness: {}", level.to_string());
}
Some(level) => writer.write_brightness(level)?,
}
}
if let Some(fan_level) = parsed.pwr_profile {
writer.write_fan_mode(fan_level.into())?;
}
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "asus-nb"
version = "2.0.4"
version = "2.1.0"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+67 -33
View File
@@ -1,16 +1,18 @@
use crate::anime_matrix::AniMePacketType;
use crate::{DBUS_IFACE, DBUS_NAME};
use dbus::channel::Sender;
use dbus::{blocking::Connection, Message};
const DBUS_ANIME_PATH : &str = "/org/asuslinux/Anime";
pub const ANIME_PANE1_PREFIX: [u8; 7] =
[0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] =
[0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
use crate::anime_matrix::{AniMeMatrix, AniMePacketType};
use crate::DBUS_NAME;
use dbus::blocking::{Connection, Proxy};
use std::error::Error;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use std::{thread, time::Duration};
pub const ANIME_PANE1_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
use crate::dbus_anime::{
OrgAsuslinuxDaemon as OrgAsuslinuxDaemonAniMe,
};
/// Interface for the AniMe dot-matrix display
///
@@ -23,7 +25,6 @@ pub const ANIME_PANE2_PREFIX: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x0
pub struct AniMeDbusWriter {
connection: Box<Connection>,
block_time: u64,
stop: Arc<AtomicBool>,
}
impl AniMeDbusWriter {
@@ -33,47 +34,80 @@ impl AniMeDbusWriter {
Ok(AniMeDbusWriter {
connection: Box::new(connection),
block_time: 25,
stop: Arc::new(AtomicBool::new(false)),
})
}
// Create D-Bus proxy
fn new_proxy(&self) -> Proxy<&Connection>{
self.connection.with_proxy(
DBUS_NAME,
DBUS_ANIME_PATH,
Duration::from_millis(200),
)
}
pub fn write_image_to_buf(_buf: &mut AniMePacketType, _image_data: &[u8]) {
unimplemented!("Image format is in progress of being worked out")
}
/// Write an Animatrix image
///
/// The expected input here is *two* Vectors, 640 bytes in length. The two vectors
/// are each one half of the full image write.
/// The expected input here is *two* Vectors, 640 bytes in length.
/// The two vectors are each one half of the full image write.
///
/// After each write a flush is written, it is assumed that this tells the device to
/// go ahead and display the written bytes
/// After each write a flush is written, it is assumed that this tells the
/// device to go ahead and display the written bytes
///
/// # Note:
/// The vectors are expected to contain the full sequence of bytes as follows
/// # Note: The vectors are expected to contain the full sequence of bytes
/// as follows
///
/// - Write packet 1: 0x5e 0xc0 0x02 0x01 0x00 0x73 0x02 .. <led brightness>
/// - Write packet 2: 0x5e 0xc0 0x02 0x74 0x02 0x73 0x02 .. <led brightness>
///
/// Where led brightness is 0..255, low to high
#[inline]
pub fn write_image(&mut self, image: &mut AniMePacketType) -> Result<(), Box<dyn Error>> {
if image[0][0] != ANIME_PANE1_PREFIX[0] && image[0][6] != ANIME_PANE1_PREFIX[6] {
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
}
if image[1][0] != ANIME_PANE2_PREFIX[0] && image[1][6] != ANIME_PANE2_PREFIX[6] {
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
}
pub fn write_image(&self, image: &mut AniMePacketType)
-> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
let mut msg =
Message::new_method_call(DBUS_NAME, "/org/asuslinux/Anime", DBUS_IFACE, "SetAnime")?
.append2(image[0].to_vec(), image[1].to_vec());
msg.set_no_reply(true);
self.connection.send(msg).unwrap();
image[0][..7].copy_from_slice(&ANIME_PANE1_PREFIX);
image[1][..7].copy_from_slice(&ANIME_PANE2_PREFIX);
proxy.set_anime(vec![image[0].to_vec(), image[1].to_vec()])?;
thread::sleep(Duration::from_millis(self.block_time));
if self.stop.load(Ordering::Relaxed) {
panic!("Got signal to stop!");
}
Ok(())
}
#[inline]
pub fn set_leds_brightness(&self, led_brightness: u8)
-> Result<(), Box<dyn Error>> {
let mut anime_matrix = AniMeMatrix::new();
anime_matrix.fill_with(led_brightness);
self.write_image(&mut AniMePacketType::from(anime_matrix))?;
Ok(())
}
fn turn_on_off(&self, status : bool) -> Result<(), Box<dyn Error>> {
let proxy = self.new_proxy();
proxy.set_on_off(status)?;
thread::sleep(Duration::from_millis(self.block_time));
Ok(())
}
#[inline]
pub fn turn_on(&self) -> Result<(), Box<dyn Error>> {
self.turn_on_off(true)?;
Ok(())
}
#[inline]
pub fn turn_off(&self) -> Result<(), Box<dyn Error>> {
self.turn_on_off(false)?;
Ok(())
}
}
+46 -7
View File
@@ -5,10 +5,14 @@ use std::str::FromStr;
#[derive(Options)]
pub struct LedBrightness {
level: u8,
level: Option<u8>,
}
impl LedBrightness {
pub fn level(&self) -> u8 {
pub fn new(level: Option<u8>) -> Self {
LedBrightness { level }
}
pub fn level(&self) -> Option<u8> {
self.level
}
}
@@ -18,17 +22,30 @@ impl FromStr for LedBrightness {
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"off" => Ok(LedBrightness { level: 0x00 }),
"low" => Ok(LedBrightness { level: 0x01 }),
"med" => Ok(LedBrightness { level: 0x02 }),
"high" => Ok(LedBrightness { level: 0x03 }),
"off" => Ok(LedBrightness { level: Some(0x00) }),
"low" => Ok(LedBrightness { level: Some(0x01) }),
"med" => Ok(LedBrightness { level: Some(0x02) }),
"high" => Ok(LedBrightness { level: Some(0x03) }),
_ => {
println!("Missing required argument, must be one of:\noff,low,med,high\n");
print!("{}\n{}\n",
"Invalid argument, must be one of:",
"off, low, med, high");
Err(AuraError::ParseBrightness)
}
}
}
}
impl ToString for LedBrightness {
fn to_string(&self) -> String {
let s = match self.level {
Some(0x00) => "low",
Some(0x01) => "med",
Some(0x02) => "high",
_ => "unknown",
};
s.to_string()
}
}
#[derive(Deserialize, Serialize)]
pub struct Colour(pub u8, pub u8, pub u8);
@@ -213,3 +230,25 @@ impl Default for SetAuraBuiltin {
})
}
}
#[derive(Options)]
pub struct AniMeLeds {
#[options(help = "print help message")]
help: bool,
#[options(no_long, required,
short = "b", meta = "BYTE",
help = "set all leds brightness value")]
led_brightness: u8,
}
impl AniMeLeds {
pub fn led_brightness(&self) -> u8 {
self.led_brightness
}
}
#[derive(Options)]
pub enum AniMeActions {
#[options(help = "change all leds brightness")]
Leds(AniMeLeds),
}
+49 -2
View File
@@ -1,3 +1,4 @@
use crate::cli_options::LedBrightness;
use super::*;
use crate::fancy::KeyColourArray;
use crate::profile::ProfileEvent;
@@ -230,6 +231,28 @@ impl AuraDbusClient {
Ok(())
}
#[inline]
pub fn next_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.next_led_mode()?;
Ok(())
}
#[inline]
pub fn prev_keyboard_led_mode(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
proxy.prev_led_mode()?;
Ok(())
}
#[inline]
pub fn get_gfx_pwr(&self) -> Result<String, Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
@@ -263,6 +286,17 @@ impl AuraDbusClient {
Ok(())
}
#[inline]
pub fn next_fan_profile(&self) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Profile",
Duration::from_secs(2),
);
proxy.next_profile()?;
Ok(())
}
#[inline]
pub fn write_fan_mode(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
let proxy = self.connection.with_proxy(
@@ -305,8 +339,21 @@ impl AuraDbusClient {
}
#[inline]
pub fn write_brightness(&self, level: u8) -> Result<String, Box<dyn std::error::Error>> {
pub fn get_led_brightness(&self) -> Result<LedBrightness, Box<dyn Error>> {
let proxy = self.connection.with_proxy(
"org.asuslinux.Daemon",
"/org/asuslinux/Led",
Duration::from_secs(2),
);
match proxy.led_brightness()? {
-1 => Ok(LedBrightness::new(None)),
level => Ok(LedBrightness::new(Some(level as u8))),
}
}
#[inline]
pub fn write_brightness(&self, level: u8) -> Result<(), Box<dyn std::error::Error>> {
self.write_keyboard_leds(&AuraModes::LedBrightness(level))?;
Ok(String::new())
Ok(())
}
}
+21
View File
@@ -0,0 +1,21 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Anime -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error>;
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn set_anime(&self, input: Vec<Vec<u8>>) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetAnime", (input, ))
}
fn set_on_off(&self, status: bool) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetOnOff", (status, ))
}
}
+16
View File
@@ -6,8 +6,11 @@ use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_led_mode(&self, data: &str) -> Result<(), dbus::Error>;
fn next_led_mode(&self) -> Result<(), dbus::Error>;
fn prev_led_mode(&self) -> Result<(), dbus::Error>;
fn led_mode(&self) -> Result<String, dbus::Error>;
fn led_modes(&self) -> Result<String, dbus::Error>;
fn led_brightness(&self) -> Result<i16, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
@@ -16,6 +19,14 @@ impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslin
self.method_call("org.asuslinux.Daemon", "SetLedMode", (data, ))
}
fn next_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextLedMode", ())
}
fn prev_led_mode(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "PrevLedMode", ())
}
fn led_mode(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedMode", ())
.and_then(|r: (String, )| Ok(r.0, ))
@@ -25,6 +36,11 @@ impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslin
self.method_call("org.asuslinux.Daemon", "LedModes", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn led_brightness(&self) -> Result<i16, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "LedBrightness", ())
.and_then(|r: (i16, )| Ok(r.0, ))
}
}
#[derive(Debug)]
+21 -9
View File
@@ -1,30 +1,40 @@
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -f org.asuslinux.Daemon -c blocking -p /org/asuslinux/Profile -m None`, see https://github.com/diwic/dbus-rs
use dbus;
// This code was autogenerated with `dbus-codegen-rust -s -d org.asuslinux.Daemon -p /org/asuslinux/Profile -m None -f org.asuslinux.Daemon -c blocking`, see https://github.com/diwic/dbus-rs
use dbus as dbus;
#[allow(unused_imports)]
use dbus::arg;
use dbus::blocking;
pub trait OrgAsuslinuxDaemon {
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error>;
fn next_profile(&self) -> Result<(), dbus::Error>;
fn active_profile_name(&self) -> Result<String, dbus::Error>;
fn profile(&self) -> Result<String, dbus::Error>;
fn profiles(&self) -> Result<String, dbus::Error>;
}
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target = T>> OrgAsuslinuxDaemon
for blocking::Proxy<'a, C>
{
impl<'a, T: blocking::BlockingSender, C: ::std::ops::Deref<Target=T>> OrgAsuslinuxDaemon for blocking::Proxy<'a, C> {
fn set_profile(&self, profile: &str) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile,))
self.method_call("org.asuslinux.Daemon", "SetProfile", (profile, ))
}
fn next_profile(&self) -> Result<(), dbus::Error> {
self.method_call("org.asuslinux.Daemon", "NextProfile", ())
}
fn active_profile_name(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "ActiveProfileName", ())
.and_then(|r: (String, )| Ok(r.0, ))
}
fn profile(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profile", ())
.and_then(|r: (String,)| Ok(r.0))
.and_then(|r: (String, )| Ok(r.0, ))
}
fn profiles(&self) -> Result<String, dbus::Error> {
self.method_call("org.asuslinux.Daemon", "Profiles", ())
.and_then(|r: (String,)| Ok(r.0))
.and_then(|r: (String, )| Ok(r.0, ))
}
}
@@ -41,7 +51,9 @@ impl arg::AppendAll for OrgAsuslinuxDaemonNotifyProfile {
impl arg::ReadAll for OrgAsuslinuxDaemonNotifyProfile {
fn read(i: &mut arg::Iter) -> Result<Self, arg::TypeMismatchError> {
Ok(OrgAsuslinuxDaemonNotifyProfile { profile: i.read()? })
Ok(OrgAsuslinuxDaemonNotifyProfile {
profile: i.read()?,
})
}
}
+2
View File
@@ -7,6 +7,7 @@ pub enum AuraError {
ParseSpeed,
ParseDirection,
ParseBrightness,
ParseAnime,
}
impl fmt::Display for AuraError {
@@ -17,6 +18,7 @@ impl fmt::Display for AuraError {
AuraError::ParseSpeed => write!(f, "Could not parse speed"),
AuraError::ParseDirection => write!(f, "Could not parse direction"),
AuraError::ParseBrightness => write!(f, "Could not parse brightness"),
AuraError::ParseAnime => write!(f, "Could not parse anime"),
}
}
}
+1
View File
@@ -27,6 +27,7 @@ pub mod dbus_gfx;
pub mod dbus_ledmode;
pub mod dbus_profile;
pub mod dbus_charge;
pub mod dbus_anime;
pub mod error;
+2
View File
@@ -76,6 +76,8 @@ fn parse_fan_curve(data: &str) -> Result<Curve, String> {
pub struct ProfileCommand {
#[options(help = "print help message")]
help: bool,
#[options(help = "toggle to next profile in list")]
pub next: bool,
#[options(help = "create the profile if it doesn't exist")]
pub create: bool,
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "ctrl-gfx"
version = "2.1.1"
version = "2.1.3"
license = "MPL-2.0"
readme = "README.md"
authors = ["Luke <luke@ljones.dev>"]
+50
View File
@@ -0,0 +1,50 @@
function _asusctl() {
local line
_arguments -C \
{-h,--help}'[print help message]' \
{-v,--version}'[print version number]' \
{-k,--kbd-bright}':[Set keyboard brightness (off, low, med, high)]' \
{-p,--pwr-profile}':[Set power profile (silent, normal, boost)]' \
{-c,--chg-limit}':[Set charging limit (20-100)]' \
': :((led-mode\:"Set the keyboard lighting from built-in modes" profile\:"Create and configure profiles" graphics\:"Set the graphics mode"))' \
'*::arg:->args'
case $line[1] in
led-mode)
_arguments ': :((static\:"set a single static colour"
breathe\:"pulse between one or two colours"
strobe\:"strobe through all colours"
rainbow\:"rainbow cycling in one of four directions"
star\:"rain pattern mimicking raindrops"
rain\:"rain pattern of three preset colours"
highlight\:"pressed keys are highlighted to fade"
laser\:"pressed keys generate horizontal laser"
ripple\:"pressed keys ripple outwards like a splash"
pulse\:"set a rapid pulse"
comet\:"set a vertical line zooming from left"
flash\:"set a wide vertical line zooming from left"
multi-static\:"4-zone multi-colour"))' \
{-h,--help}'[print help message]' \
'-c:[set the RGB value e.g, ff00ff]' \
'-s:[set the speed (low, med, high)]'
;;
profile)
_arguments {-h,--help}'[print help message]' \
{-c,--create}"[create the profile if it doesn't exist]" \
{-t,--turbo}':[enable or disable cpu turbo]' \
{-m,--min-percentage}':[set min cpu scaling (intel)]' \
{-M,--max-percentage}':[set max cpu scaling (intel)]' \
{-p,--preset}':[<silent, normal, boost>]' \
{-C,--curve}':[set fan curve]'
;;
graphics)
_arguments {-h,--help}'[print help message]' \
{-m,--mode}':[Set graphics mode (nvidia, hybrid, compute, integrated)]' \
{-g,--get}'[Get the current mode]' \
{-p,--pow}'[Get the current power status]' \
{-f,--force}'[Do not ask for confirmation]'
;;
esac
}
compdef _asusctl asusctl
+1 -1
View File
@@ -4,9 +4,9 @@ StartLimitInterval=200
StartLimitBurst=2
[Service]
ExecStartPre=/usr/bin/sleep 2
ExecStart=/usr/bin/asus-notify
Restart=on-failure
Restart=always
RestartSec=1
Type=simple