diff --git a/Cargo.lock b/Cargo.lock
index 672b9e86..592eb7ee 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -42,6 +42,16 @@ dependencies = [
"cfg-if",
]
+[[package]]
+name = "dbus"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "add8dd36d6d34a084220eb9fe216d3e230d52b37c31702e1ffda4fb2d4ef950e"
+dependencies = [
+ "libc",
+ "libdbus-sys",
+]
+
[[package]]
name = "filetime"
version = "0.2.9"
@@ -80,6 +90,15 @@ version = "0.2.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0"
+[[package]]
+name = "libdbus-sys"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc12a3bc971424edbbf7edaf6e5740483444db63aa8e23d3751ff12a30f306f0"
+dependencies = [
+ "pkg-config",
+]
+
[[package]]
name = "libflate"
version = "0.1.27"
@@ -144,8 +163,9 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
[[package]]
name = "rog-core"
-version = "0.1.0"
+version = "0.2.0"
dependencies = [
+ "dbus",
"gumdrop",
"rusb",
]
diff --git a/Cargo.toml b/Cargo.toml
index 65f25a8c..b2151c7a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,3 +7,4 @@ edition = "2018"
[dependencies]
rusb = "0.5"
gumdrop = "0.8"
+dbus = "0.7.1"
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..3504bb51
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,59 @@
+prefix ?= /usr
+sysconfdir ?= /etc
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+datarootdir = $(prefix)/share
+datadir = $(datarootdir)
+
+SRC = Cargo.toml Cargo.lock Makefile $(shell find src -type f -wholename '*src/*.rs')
+
+.PHONY: all clean distclean install uninstall update
+
+BIN=rog-core
+
+DEBUG ?= 0
+ifeq ($(DEBUG),0)
+ ARGS += "--release"
+ TARGET = release
+endif
+
+VENDORED ?= 0
+ifeq ($(VENDORED),1)
+ ARGS += "--frozen"
+endif
+
+all: target/release/$(BIN)
+
+clean:
+ cargo clean
+
+distclean:
+ rm -rf .cargo vendor vendor.tar.xz
+
+install: all
+ install -D -m 04755 "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"
+
+uninstall:
+ rm -f "$(DESTDIR)$(bindir)/$(BIN)"
+ rm -f "$(DESTDIR)$(sysconfdir)/dbus-1/system.d/$(BIN).conf"
+ rm -f "$(DESTDIR)$(libdir)/systemd/system/$(BIN).service"
+
+update:
+ cargo update
+
+vendor:
+ mkdir -p .cargo
+ cargo vendor | head -n -1 > .cargo/config
+ echo 'directory = "vendor"' >> .cargo/config
+ tar pcfJ vendor.tar.xz vendor
+ rm -rf vendor
+
+target/release/$(BIN): $(SRC)
+ifeq ($(VENDORED),1)
+ tar pxf vendor.tar.xz
+endif
+ cargo build $(ARGS)
diff --git a/data/rog-core.conf b/data/rog-core.conf
new file mode 100644
index 00000000..f6c4a1f9
--- /dev/null
+++ b/data/rog-core.conf
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/data/rog-core.service b/data/rog-core.service
new file mode 100644
index 00000000..b5183b96
--- /dev/null
+++ b/data/rog-core.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=ROG Core Daemon
+
+[Service]
+ExecStart=/usr/bin/rog-core -d
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/src/aura.rs b/src/aura.rs
index 9b50e045..d8bca0d8 100644
--- a/src/aura.rs
+++ b/src/aura.rs
@@ -1,45 +1,11 @@
use crate::core::LED_MSG_LEN;
+use crate::error::AuraError;
use gumdrop::Options;
-use std::error::Error;
-use std::fmt;
-use std::fmt::{Debug, Display};
+use std::fmt::Debug;
use std::str::FromStr;
-#[derive(PartialEq)]
-pub enum AuraError {
- ParseColour,
- ParseSpeed,
- ParseDirection,
- ParseBrightness,
-}
-
-impl Debug for AuraError {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Display::fmt(self.description(), f)
- }
-}
-
-impl Display for AuraError {
- #[inline]
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- Display::fmt(self.description(), f)
- }
-}
-
-impl Error for AuraError {
- fn description(&self) -> &str {
- match self {
- AuraError::ParseColour => "could not parse colour",
- AuraError::ParseSpeed => "could not parse speed",
- AuraError::ParseDirection => "could not parse direction",
- AuraError::ParseBrightness => "could not parse brightness",
- }
- }
-}
-
#[derive(Debug, PartialEq)]
-pub struct Colour(u8, u8, u8);
+pub(crate) struct Colour(u8, u8, u8);
impl Default for Colour {
fn default() -> Self {
Colour(255, 0, 0)
@@ -60,7 +26,7 @@ impl FromStr for Colour {
}
#[derive(Debug, PartialEq)]
-pub enum Speed {
+pub(crate) enum Speed {
Low = 0xe1,
Med = 0xeb,
High = 0xf5,
@@ -88,7 +54,7 @@ impl FromStr for Speed {
///
/// Enum corresponds to the required integer value
#[derive(Debug, PartialEq)]
-pub enum Direction {
+pub(crate) enum Direction {
Right,
Left,
Up,
@@ -115,7 +81,7 @@ impl FromStr for Direction {
}
#[derive(Debug, PartialEq, Options)]
-pub struct Breathe {
+pub(crate) struct Breathe {
#[options(help = "print help message")]
help: bool,
#[options(no_long, help = "set the first colour, must be hex string e.g, ff00ff")]
@@ -130,7 +96,7 @@ pub struct Breathe {
}
#[derive(Debug, PartialEq, Options)]
-pub struct SingleSpeed {
+pub(crate) struct SingleSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, help = "set the speed: low, med, high")]
@@ -138,7 +104,7 @@ pub struct SingleSpeed {
}
#[derive(Debug, PartialEq, Options)]
-pub struct SingleColour {
+pub(crate) struct SingleColour {
#[options(help = "print help message")]
help: bool,
#[options(no_long, help = "set the colour, must be hex string e.g, ff00ff")]
@@ -146,7 +112,7 @@ pub struct SingleColour {
}
#[derive(Debug, PartialEq, Options)]
-pub struct SingleSpeedDirection {
+pub(crate) struct SingleSpeedDirection {
#[options(help = "print help message")]
help: bool,
#[options(no_long, help = "set the direction: up, down, left, right")]
@@ -156,7 +122,7 @@ pub struct SingleSpeedDirection {
}
#[derive(Debug, PartialEq, Options)]
-pub struct SingleColourSpeed {
+pub(crate) struct SingleColourSpeed {
#[options(help = "print help message")]
help: bool,
#[options(no_long, help = "set the colour, must be hex string e.g, ff00ff")]
@@ -169,7 +135,7 @@ pub struct SingleColourSpeed {
///
/// Enum corresponds to the required integer value
#[derive(Debug, Options)]
-pub enum SetAuraBuiltin {
+pub(crate) enum SetAuraBuiltin {
#[options(help = "set a single static colour")]
Stable(SingleColour),
#[options(help = "pulse between one or two colours")]
@@ -247,7 +213,7 @@ impl Default for SetAuraBuiltin {
/// - 0x03 = downwards
///
/// Bytes 10, 11, 12 are Red, Green, Blue for second colour if mode supports it
-pub struct ModeMessage(pub [u8; LED_MSG_LEN]);
+pub(crate) struct ModeMessage(pub [u8; LED_MSG_LEN]);
impl From for ModeMessage {
fn from(mode: SetAuraBuiltin) -> Self {
diff --git a/src/core.rs b/src/core.rs
index aa6aa0b0..59912f39 100644
--- a/src/core.rs
+++ b/src/core.rs
@@ -1,5 +1,7 @@
-use crate::aura::AuraError;
-use crate::aura::ModeMessage;
+use crate::error::AuraError;
+use crate::{DBUS_IFACE, DBUS_NAME, DBUS_PATH};
+use dbus::Error as DbusError;
+use dbus::{ffidisp::Connection, Message};
use gumdrop::Options;
use rusb::{DeviceHandle, Error};
use std::str::FromStr;
@@ -17,7 +19,7 @@ static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
static LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
#[derive(Debug, Options)]
-pub struct LedBrightness {
+pub(crate) struct LedBrightness {
pub level: u8,
}
impl FromStr for LedBrightness {
@@ -47,7 +49,7 @@ impl FromStr for LedBrightness {
/// - `LED_INIT4`
/// - `LED_INIT2`
/// - `LED_INIT4`
-pub struct RogCore {
+pub(crate) struct RogCore {
handle: DeviceHandle,
initialised: bool,
led_interface_num: u8,
@@ -96,7 +98,7 @@ impl RogCore {
Err(Error::NoDevice)
}
- fn aura_write_messages(&mut self, messages: &[[u8; LED_MSG_LEN]]) -> Result<(), Error> {
+ fn aura_write_messages(&mut self, messages: &[&[u8]]) -> Result<(), Error> {
self.handle.claim_interface(self.led_interface_num)?;
// Declared as a zoomy so that it is hidden
let write = |message: &[u8]| {
@@ -114,7 +116,7 @@ impl RogCore {
for message in messages {
println!("{:x?}", &message);
- write(message)?;
+ write(*message)?;
write(&LED_SET)?;
}
// Changes won't persist unless apply is set
@@ -124,19 +126,31 @@ impl RogCore {
Ok(())
}
- pub fn aura_set_brightness(&mut self, brightness: u8) -> Result<(), Error> {
+ pub fn aura_brightness_bytes(brightness: u8) -> Result<[u8; 17], Error> {
let mut bright = [0u8; LED_MSG_LEN];
bright[0] = 0x5a;
bright[1] = 0xba;
bright[2] = 0xc5;
bright[3] = 0xc4;
bright[4] = brightness;
- let messages = [bright];
- self.aura_write_messages(&messages)
+ Ok(bright)
}
- pub fn aura_set_mode(&mut self, mode: ModeMessage) -> Result<(), Error> {
- let messages = [mode.0];
+ pub fn aura_set_mode(&mut self, mode: &[u8]) -> Result<(), Error> {
+ let messages = [mode];
self.aura_write_messages(&messages)
}
}
+
+pub(super) fn dbus_led_builtin_write(bytes: &[u8]) -> Result<(), Box> {
+ let bus = Connection::new_system()?;
+ //let proxy = bus.with_proxy(DBUS_IFACE, "/", Duration::from_millis(5000));
+ let msg = Message::new_method_call(DBUS_NAME, DBUS_PATH, DBUS_IFACE, "ledmessage")?
+ .append1(bytes.to_vec());
+ let r = bus.send_with_reply_and_block(msg, 5000)?;
+ if let Some(reply) = r.get1::<&str>() {
+ println!("Daemon sez: {}", reply);
+ return Ok(());
+ }
+ Err(Box::new(DbusError::new_custom("name", "message")))
+}
diff --git a/src/daemon.rs b/src/daemon.rs
new file mode 100644
index 00000000..7120d29b
--- /dev/null
+++ b/src/daemon.rs
@@ -0,0 +1,55 @@
+use crate::{core::RogCore, DBUS_IFACE, DBUS_PATH};
+use dbus::{
+ blocking::Connection,
+ tree::{Factory, MethodErr},
+};
+use std::error::Error;
+use std::time::Duration;
+
+pub fn start_daemon() -> Result<(), Box> {
+ let mut c = Connection::new_system()?;
+ c.request_name(DBUS_IFACE, false, true, false)?;
+
+ // The choice of factory tells us what type of tree we want,
+ // and if we want any extra data inside. We pick the simplest variant.
+ let f = Factory::new_fn::<()>();
+
+ // We create a tree with one object path inside and make that path introspectable.
+ let tree = f.tree(()).add(
+ f.object_path(DBUS_PATH, ()).introspectable().add(
+ // We add an interface to the object path...
+ f.interface(DBUS_IFACE, ())
+ // ...and a method inside the interface
+ .add_m(
+ f.method("ledmessage", (), move |m| {
+ // Reads the args passed to the method
+ // Reads the args passed to the method
+ let bytes: Vec = m.msg.read1()?;
+ let s = format!("Shoving {:x?} in to keyboard!", bytes);
+
+ if let Ok(mut core) = RogCore::new() {
+ match core.aura_set_mode(&bytes[..]) {
+ Ok(_) => {
+ let mret = m.msg.method_return().append1(s);
+ Ok(vec![mret])
+ }
+ Err(err) => Err(MethodErr::failed(&err)),
+ }
+ } else {
+ Err(MethodErr::failed("Failed to start RogCore"))
+ }
+ })
+ // Input?
+ .outarg::<&str, _>("reply")
+ .inarg::, _>("bytearray"),
+ ),
+ ),
+ );
+
+ // We add the tree to the connection so that incoming method calls will be handled.
+ tree.start_receive(&c);
+
+ loop {
+ c.process(Duration::from_secs(1))?;
+ }
+}
diff --git a/src/error.rs b/src/error.rs
new file mode 100644
index 00000000..b49d61ef
--- /dev/null
+++ b/src/error.rs
@@ -0,0 +1,36 @@
+use std::error::Error;
+use std::fmt;
+use std::fmt::{Debug, Display};
+
+#[derive(PartialEq)]
+pub(crate) enum AuraError {
+ ParseColour,
+ ParseSpeed,
+ ParseDirection,
+ ParseBrightness,
+}
+
+impl Debug for AuraError {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(self.description(), f)
+ }
+}
+
+impl Display for AuraError {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ Display::fmt(self.description(), f)
+ }
+}
+
+impl Error for AuraError {
+ fn description(&self) -> &str {
+ match self {
+ AuraError::ParseColour => "could not parse colour",
+ AuraError::ParseSpeed => "could not parse speed",
+ AuraError::ParseDirection => "could not parse direction",
+ AuraError::ParseBrightness => "could not parse brightness",
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index cf28b9d5..f1f06577 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,15 +1,26 @@
// TODO: use /sys/class/dmi/id/board_name to detect model
mod aura;
mod core;
+mod daemon;
+mod error;
use crate::aura::*;
-use crate::core::{LedBrightness, RogCore};
+use crate::core::{dbus_led_builtin_write, LedBrightness, RogCore};
+use crate::daemon::*;
use gumdrop::Options;
+pub static DBUS_NAME: &'static str = "org.rogcore.Daemon";
+pub static DBUS_PATH: &'static str = "/org/rogcore/Daemon";
+pub static DBUS_IFACE: &'static str = "org.rogcore.Daemon";
+
#[derive(Debug, Options)]
struct CLIStart {
#[options(help = "print help message")]
help: bool,
+ #[options(help = "start daemon")]
+ daemon: bool,
+ #[options(help = "client mode")]
+ client: bool,
#[options(help = "")]
bright: Option,
#[options(command)]
@@ -32,12 +43,20 @@ struct LedModeCommand {
fn main() -> Result<(), Box> {
let parsed = CLIStart::parse_args_default_or_exit();
+ if parsed.daemon {
+ start_daemon()?;
+ }
+
match parsed.command {
Some(Command::LedMode(okk)) => match okk.command {
Some(command) => {
- let mut core = RogCore::new()?;
let mode = ModeMessage::from(command);
- core.aura_set_mode(mode)?;
+ if parsed.client {
+ dbus_led_builtin_write(&mode.0)?;
+ } else {
+ let mut core = RogCore::new()?;
+ core.aura_set_mode(&mode.0)?;
+ }
}
_ => {}
},
@@ -45,8 +64,13 @@ fn main() -> Result<(), Box> {
}
match parsed.bright {
Some(brightness) => {
- let mut core = RogCore::new()?;
- core.aura_set_brightness(brightness.level as u8)?;
+ let bytes = RogCore::aura_brightness_bytes(brightness.level as u8)?;
+ if parsed.client {
+ dbus_led_builtin_write(&bytes)?;
+ } else {
+ let mut core = RogCore::new()?;
+ core.aura_set_mode(&bytes)?;
+ }
}
_ => {}
}