From 229fa93bc7c8495c3637d84895cf65a9be598bb7 Mon Sep 17 00:00:00 2001 From: Luke Jones Date: Tue, 7 Jul 2020 13:33:32 +1200 Subject: [PATCH] Dbus signals (#28) * Small rename of dbus args * Split out parts of main loop to tasks * Send signals on boot --- Makefile | 2 +- README_DBUS.md | 22 ++++ data/rog-core.service | 2 + rog-client/examples/ball.rs | 3 +- rog-core/src/daemon.rs | 194 ++++++++++++++++++++++++++++-------- rog-core/src/rog_dbus.rs | 18 ++-- 6 files changed, 186 insertions(+), 55 deletions(-) diff --git a/Makefile b/Makefile index ecf8b03f..bf98b26e 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ distclean: rm -rf .cargo vendor vendor.tar.xz install: all - install -D -m 04755 "target/release/$(BIN)" "$(DESTDIR)$(bindir)/$(BIN)" + install -D -m 0755 "target/release/$(BIN)" "$(DESTDIR)$(bindir)/$(BIN)" install -D -m 0644 "data/$(BIN).conf" "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN).conf" install -D -m 0644 "data/$(BIN).service" "$(DESTDIR)$(libdir)/systemd/system/$(BIN).service" diff --git a/README_DBUS.md b/README_DBUS.md index 1a0da9ba..e11678e1 100644 --- a/README_DBUS.md +++ b/README_DBUS.md @@ -131,6 +131,28 @@ When emitted, it will include the integer the charging limit was changed to. dbus-send --system --type=method_call --dest=org.rogcore.Daemon /org/rogcore/Daemon org.rogcore.Daemon.SetKeyBacklight string:'{"Stable": {"colour": [ 80, 0, 40]}}' ``` +``` +dbus-send --system --type=method_call --dest=org.rogcore.Daemon /org/rogcore/Daemon org.rogcore.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,0],"speed":"Med"}}' +``` + +**Note:** setting colour2 to `[0,0,255]` activates random star colour. Colour2 has no effect on the +mode otherwise. +``` +dbus-send --system --type=method_call --dest=org.rogcore.Daemon /org/rogcore/Daemon org.rogcore.Daemon.SetKeyBacklight string:'{"Star":{"colour":[0,255,255],"colour2":[0,0,255],"speed":"Med"}}' +``` + ``` dbus-send --system --type=method_call --dest=org.rogcore.Daemon /org/rogcore/Daemon org.rogcore.Daemon.SetKeyBacklight string:'{"LedBrightness":3}' +``` + +``` +dbus-send --system --type=method_call --dest=org.rogcore.Daemon /org/rogcore/Daemon org.rogcore.Daemon.SetFanMode byte:'2' +``` + +Monitoring dbus while sending commands via `rog-core` will give you the json structure if you are otherwise unsure, e.g: `dbus-monitor --system |grep -A2 rogcore`. + +## Getting an introspection .xml + +``` +dbus-send --system --print-reply --dest=org.rogcore.Daemon /org/rogcore/Daemon org.freedesktop.DBus.Introspectable.Introspect > xml/dbus-0.14.4.xml ``` \ No newline at end of file diff --git a/data/rog-core.service b/data/rog-core.service index b5183b96..abbdb935 100644 --- a/data/rog-core.service +++ b/data/rog-core.service @@ -4,6 +4,8 @@ Description=ROG Core Daemon [Service] ExecStart=/usr/bin/rog-core -d Restart=on-failure +Type=dbus +BusName=org.rogcore.Daemon [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/rog-client/examples/ball.rs b/rog-client/examples/ball.rs index c5bcc428..f2210da6 100644 --- a/rog-client/examples/ball.rs +++ b/rog-client/examples/ball.rs @@ -24,7 +24,8 @@ impl Ball { } } - fn update(&mut self, key_map: &Vec<[Key; 17]>) { + #[allow(clippy::if_same_then_else)] + fn update(&mut self, key_map: &[[Key; 17]]) { let pos = self.position; let dir = self.direction; diff --git a/rog-core/src/daemon.rs b/rog-core/src/daemon.rs index 3ff50acd..095e5fc8 100644 --- a/rog-core/src/daemon.rs +++ b/rog-core/src/daemon.rs @@ -7,13 +7,14 @@ use crate::{ rogcore::*, }; -use dbus::{channel::Sender, nonblock::Process}; +use dbus::{channel::Sender, nonblock::Process, nonblock::SyncConnection, tree::Signal}; use dbus_tokio::connection; use log::{error, info, warn}; use rog_client::{aura_modes::AuraModes, DBUS_IFACE, DBUS_NAME, DBUS_PATH}; use std::error::Error; use std::sync::Arc; + use tokio::sync::Mutex; pub(super) type DbusU8Type = Arc>>; @@ -62,6 +63,13 @@ pub async fn start_daemon() -> Result<(), Box> { laptop.led_endpoint(), laptop.supported_modes().to_owned(), ); + + let keyboard_reader = KeyboardReader::new( + rogcore.get_raw_device_handle(), + laptop.key_endpoint(), + laptop.key_filter().to_owned(), + ); + led_writer .reload_last_builtin(&mut config) .await @@ -86,20 +94,33 @@ pub async fn start_daemon() -> Result<(), Box> { mut animatrix_recv, fan_mode, charge_limit, - effect_cancel_signal, + led_changed_signal, fanmode_signal, charge_limit_signal, ) = dbus_create_tree(config.clone()); // We add the tree to the connection so that incoming method calls will be handled. tree.start_receive_send(&*connection); + // Send boot signals + send_boot_signals( + connection.clone(), + config.clone(), + fanmode_signal.clone(), + charge_limit_signal.clone(), + led_changed_signal.clone(), + ) + .await?; + + // For helping with processing signals + start_signal_task( + connection.clone(), + config.clone(), + fanmode_signal, + charge_limit_signal, + ); + // Keyboard reader goes in separate task because we want a high interrupt timeout // and don't want that to hold up other tasks, or miss keystrokes - let keyboard_reader = KeyboardReader::new( - rogcore.get_raw_device_handle(), - laptop.key_endpoint(), - laptop.key_filter().to_owned(), - ); // Possible Animatrix if laptop.support_animatrix() { @@ -117,8 +138,9 @@ pub async fn start_daemon() -> Result<(), Box> { } } - let config1 = config.clone(); // start the keyboard reader and laptop-action loop + let config1 = config.clone(); + // spawning this in a function causes a segfault for reasons I haven't investigated yet tokio::spawn(async move { loop { // Fan mode @@ -150,41 +172,6 @@ pub async fn start_daemon() -> Result<(), Box> { } }); - // For helping with processing signals - let connection1 = connection.clone(); - let config1 = config.clone(); - tokio::spawn(async move { - // Some small things we need to track, without passing all sorts of stuff around - let mut last_fan_mode = config1.lock().await.fan_mode; - let mut last_charge_limit = config1.lock().await.bat_charge_limit; - loop { - // Use tokio sleep to not hold up other threads - tokio::time::delay_for(std::time::Duration::from_millis(500)).await; - - let config = config1.lock().await; - if config.fan_mode != last_fan_mode { - last_fan_mode = config.fan_mode; - connection1 - .send( - fanmode_signal - .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) - .append1(last_fan_mode), - ) - .unwrap_or_else(|_| 0); - } - if config.bat_charge_limit != last_charge_limit { - last_charge_limit = config.bat_charge_limit; - connection1 - .send( - charge_limit_signal - .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) - .append1(last_charge_limit), - ) - .unwrap_or_else(|_| 0); - } - } - }); - // start the main loop loop { connection.process_all(); @@ -206,7 +193,7 @@ pub async fn start_daemon() -> Result<(), Box> { .unwrap_or_else(|err| warn!("{}", err)); connection .send( - effect_cancel_signal + led_changed_signal .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) .append1(json), ) @@ -216,3 +203,122 @@ pub async fn start_daemon() -> Result<(), Box> { } } } + +fn start_signal_task( + connection: Arc, + config: Arc>, + fanmode_signal: Arc>, + charge_limit_signal: Arc>, +) { + tokio::spawn(async move { + // Some small things we need to track, without passing all sorts of stuff around + let mut last_fan_mode = config.lock().await.fan_mode; + let mut last_charge_limit = config.lock().await.bat_charge_limit; + loop { + // Use tokio sleep to not hold up other threads + tokio::time::delay_for(std::time::Duration::from_millis(500)).await; + + let config = config.lock().await; + if config.fan_mode != last_fan_mode { + last_fan_mode = config.fan_mode; + connection + .send( + fanmode_signal + .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) + .append1(last_fan_mode), + ) + .unwrap_or_else(|_| 0); + } + if config.bat_charge_limit != last_charge_limit { + last_charge_limit = config.bat_charge_limit; + connection + .send( + charge_limit_signal + .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) + .append1(last_charge_limit), + ) + .unwrap_or_else(|_| 0); + } + } + }); +} + +async fn send_boot_signals( + connection: Arc, + config: Arc>, + fanmode_signal: Arc>, + charge_limit_signal: Arc>, + led_changed_signal: Arc>, +) -> Result<(), Box> { + let config = config.lock().await; + if let Some(data) = config.get_led_mode_data(config.current_mode) { + connection + .send( + led_changed_signal + .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) + .append1(serde_json::to_string(data)?), + ) + .unwrap_or_else(|_| 0); + } + connection + .send( + fanmode_signal + .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) + .append1(config.fan_mode), + ) + .unwrap_or_else(|_| 0); + connection + .send( + charge_limit_signal + .msg(&DBUS_PATH.into(), &DBUS_IFACE.into()) + .append1(config.bat_charge_limit), + ) + .unwrap_or_else(|_| 0); + Ok(()) +} + +// fn start_keyboard_task( +// fan_mode: Arc>>, +// charge_limit: Arc>>, +// config: Arc>, +// aura_command_sender: mpsc::Sender, +// mut rogcore: RogCore, +// laptop: LaptopBase, +// ) -> tokio::task::JoinHandle<()> { +// let keyboard_reader = KeyboardReader::new( +// rogcore.get_raw_device_handle(), +// laptop.key_endpoint(), +// laptop.key_filter().to_owned(), +// ); +// +// tokio::spawn(async move { +// loop { +// // Fan mode +// if let Ok(mut lock) = fan_mode.try_lock() { +// if let Some(n) = lock.take() { +// let mut config = config.lock().await; +// rogcore +// .set_fan_mode(n, &mut config) +// .unwrap_or_else(|err| warn!("{:?}", err)); +// } +// } +// // Charge limit +// if let Ok(mut lock) = charge_limit.try_lock() { +// if let Some(n) = lock.take() { +// let mut config = config.lock().await; +// rogcore +// .set_charge_limit(n, &mut config) +// .unwrap_or_else(|err| warn!("{:?}", err)); +// } +// } +// // Keyboard reads +// let data = keyboard_reader.poll_keyboard().await; +// if let Some(bytes) = data { +// laptop +// .run(&mut rogcore, &config, bytes, aura_command_sender.clone()) +// .await +// .unwrap_or_else(|err| warn!("{}", err)); +// } +// } +// }) +// } diff --git a/rog-core/src/rog_dbus.rs b/rog-core/src/rog_dbus.rs index 1e817cce..a2bf5be5 100644 --- a/rog-core/src/rog_dbus.rs +++ b/rog-core/src/rog_dbus.rs @@ -55,7 +55,7 @@ fn get_keyboard_backlight(config: Arc>) -> Method { } } }) - .outarg::<&str, _>("value") + .outarg::<&str, _>("json") } fn get_keyboard_backlight_modes(config: Arc>) -> Method { @@ -72,7 +72,7 @@ fn get_keyboard_backlight_modes(config: Arc>) -> Method("value") + .outarg::<&str, _>("json") } fn set_animatrix( @@ -115,7 +115,7 @@ fn set_fan_mode(data: DbusU8Type) -> Method { } } }) - .inarg::("byte") + .inarg::("mode") .annotate("org.freedesktop.DBus.Method.NoReply", "true") } @@ -132,7 +132,7 @@ fn get_fan_mode(config: Arc>) -> Method { } } }) - .outarg::<&str, _>("value") + .outarg::("mode") } fn get_charge_limit(config: Arc>) -> Method { @@ -148,7 +148,7 @@ fn get_charge_limit(config: Arc>) -> Method { } } }) - .outarg::<&str, _>("value") + .outarg::("limit") } fn set_charge_limit(data: DbusU8Type) -> Method { @@ -167,7 +167,7 @@ fn set_charge_limit(data: DbusU8Type) -> Method { } } }) - .inarg::("byte") + .inarg::("limit") .annotate("org.freedesktop.DBus.Method.NoReply", "true") } @@ -195,14 +195,14 @@ pub(super) fn dbus_create_tree( let key_backlight_changed = Arc::new( factory .signal("KeyBacklightChanged", ()) - .sarg::<&str, _>("value"), + .sarg::<&str, _>("json"), ); let chrg_limit_changed = Arc::new( factory .signal("ChargeLimitChanged", ()) - .sarg::("value"), + .sarg::("limit"), ); - let fanmode_changed = Arc::new(factory.signal("FanModeChanged", ()).sarg::("value")); + let fanmode_changed = Arc::new(factory.signal("FanModeChanged", ()).sarg::("mode")); let tree = factory .tree(())