Partial daemon mode for builtin LED control

This commit is contained in:
Luke
2020-04-16 15:26:13 +12:00
parent 0d5341e003
commit 2d4953d87b
10 changed files with 265 additions and 63 deletions

View File

@@ -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<SetAuraBuiltin> for ModeMessage {
fn from(mode: SetAuraBuiltin) -> Self {

View File

@@ -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<rusb::GlobalContext>,
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<dyn std::error::Error>> {
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")))
}

55
src/daemon.rs Normal file
View File

@@ -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<dyn Error>> {
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<u8> = 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::<Vec<u8>, _>("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))?;
}
}

36
src/error.rs Normal file
View File

@@ -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",
}
}
}

View File

@@ -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 = "<off, low, med, high>")]
bright: Option<LedBrightness>,
#[options(command)]
@@ -32,12 +43,20 @@ struct LedModeCommand {
fn main() -> Result<(), Box<dyn std::error::Error>> {
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<dyn std::error::Error>> {
}
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)?;
}
}
_ => {}
}