mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
CLI up
This commit is contained in:
56
Cargo.lock
generated
56
Cargo.lock
generated
@@ -54,6 +54,26 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee50908bc1beeac1f2902e0b4e0cd0d844e716f5ebdc6f0cfc1163fe5e10bcde"
|
||||
dependencies = [
|
||||
"gumdrop_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gumdrop_derive"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90454ce4de40b7ca6a8968b5ef367bdab48413962588d0d2b1638d60090c35d7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.68"
|
||||
@@ -92,6 +112,24 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.56"
|
||||
@@ -108,6 +146,7 @@ checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac"
|
||||
name = "rog-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gumdrop",
|
||||
"rusb",
|
||||
]
|
||||
|
||||
@@ -122,6 +161,17 @@ dependencies = [
|
||||
"libusb1-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "take_mut"
|
||||
version = "0.2.2"
|
||||
@@ -140,6 +190,12 @@ dependencies = [
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.8"
|
||||
|
||||
@@ -4,7 +4,6 @@ version = "0.1.0"
|
||||
authors = ["Luke <luke@ljones.dev>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rusb = "0.5"
|
||||
gumdrop = "0.7"
|
||||
|
||||
409
src/aura.rs
409
src/aura.rs
@@ -1,174 +1,245 @@
|
||||
use rusb::{DeviceHandle, Error};
|
||||
use std::time::Duration;
|
||||
use crate::core::LED_MSG_LEN;
|
||||
use gumdrop::Options;
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::str::FromStr;
|
||||
|
||||
static LED_MSG_LEN: usize = 17;
|
||||
pub static LED_SPEED_BYTES: [u8; 3] = [0xe1, 0xeb, 0xf5]; // maps to 1, 2, 3
|
||||
static LED_BRIGHT_BYTES: [u8; 5] = [0x5a, 0xba, 0xc5, 0xc4, 0]; // Index 4 = set brightness
|
||||
static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||
static LED_INIT2: &'static str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||
static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
static LED_INIT4: &'static str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||
static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
|
||||
// `LED_BUILTIN[7]` sets speed from `LED_SPEED_BYTES`
|
||||
// `LED_BUILTIN[4,5,6]` colours RGB
|
||||
// `LED_BUILTIN[3]` sets type:
|
||||
// - 00 = static
|
||||
// - 01 = breathe (can set two colours)
|
||||
// - 02 = cycle (through all colours)
|
||||
// - 03 = rainbow
|
||||
// - 04 = rain
|
||||
// - 05 = random keys, red, white, turquoise
|
||||
// - 06 = pressed keys light up and fade
|
||||
// - 07 = pressed key emits laser
|
||||
// - 08 = pressed key emits water ripple
|
||||
// - 09 = off
|
||||
// - 0a fast pulse (no speed setting)
|
||||
// - 0b vertical line racing to right (no speed setting)
|
||||
// - 0c wider vertical line racing to right (no speed setting)
|
||||
// `LED_BUILTIN[9]` sets rainbow direction:
|
||||
// - 0x00 = rightwards
|
||||
// - 0x01 = leftwards
|
||||
// - 0x02 = upwards
|
||||
// - 0x03 = downwards
|
||||
// `LED_BUILTIN[10,11,12]` 2nd colours RGB
|
||||
static LED_BUILTIN: [u8; 13] = [
|
||||
0x5d, 0xb3, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
];
|
||||
|
||||
// Only these two packets must be 17 bytes
|
||||
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 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];
|
||||
|
||||
// bytes 0,1 set mode
|
||||
// bytes 3,4,5 set to on,
|
||||
// byte 6 increments (starts at 0x00, continues 0x10 to 0xA0) 0-10 << 4
|
||||
// byte 7 resets (stays on 10 until byte6 == 0xA0 then flips to 08 in same packet as 0xA0)
|
||||
// bytes 8-57 are bitfield for keys
|
||||
static LED_SPECIAL: [u8; 64] = [
|
||||
0x5d, 0xbc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
/// ROG device controller
|
||||
///
|
||||
/// For the GX502GW the LED setup sequence looks like:
|
||||
///
|
||||
/// -` LED_INIT1`
|
||||
/// - `LED_INIT3`
|
||||
/// - `LED_INIT4`
|
||||
/// - `LED_INIT2`
|
||||
/// - `LED_INIT4`
|
||||
pub struct RogCore {
|
||||
handle: DeviceHandle<rusb::GlobalContext>,
|
||||
initialised: bool,
|
||||
led_interface_num: u8,
|
||||
keys_interface_num: u8,
|
||||
#[derive(PartialEq)]
|
||||
pub enum AuraError {
|
||||
ParseMode,
|
||||
ParseColour,
|
||||
ParseSpeed,
|
||||
ParseDirection,
|
||||
}
|
||||
|
||||
impl RogCore {
|
||||
pub fn new() -> Result<RogCore, Error> {
|
||||
let mut handle = RogCore::get_device(0x0B05, 0x1866)?;
|
||||
handle.set_active_configuration(0).unwrap_or(());
|
||||
|
||||
let config = handle.device().config_descriptor(0).unwrap();
|
||||
// Interface with outputs
|
||||
let mut keys_interface_num = 0;
|
||||
let mut led_interface_num = 0;
|
||||
for iface in config.interfaces() {
|
||||
for desc in iface.descriptors() {
|
||||
for endpoint in desc.endpoint_descriptors() {
|
||||
if endpoint.address() == 0x83 {
|
||||
keys_interface_num = desc.interface_number();
|
||||
} else if endpoint.address() == 0x81 {
|
||||
led_interface_num = desc.interface_number();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle.set_auto_detach_kernel_driver(true).unwrap();
|
||||
handle.set_auto_detach_kernel_driver(true).unwrap();
|
||||
|
||||
// let iface_out = config
|
||||
// .interfaces()
|
||||
// .nth(keys_interface_num as usize)
|
||||
// .unwrap();
|
||||
// let iface_led = config.interfaces().nth(led_interface_num as usize).unwrap();
|
||||
|
||||
//handle.claim_interface(iface_out.number()).unwrap();
|
||||
//handle.claim_interface(iface_led.number()).unwrap();
|
||||
|
||||
Ok(RogCore {
|
||||
handle,
|
||||
initialised: false,
|
||||
led_interface_num,
|
||||
keys_interface_num,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_device(vendor: u16, product: u16) -> Result<DeviceHandle<rusb::GlobalContext>, Error> {
|
||||
for device in rusb::devices().unwrap().iter() {
|
||||
let device_desc = device.device_descriptor().unwrap();
|
||||
if device_desc.vendor_id() == vendor && device_desc.product_id() == product {
|
||||
return device.open();
|
||||
}
|
||||
}
|
||||
Err(Error::NoDevice)
|
||||
}
|
||||
|
||||
fn aura_write_messages(&mut self, messages: &[Vec<u8>]) -> Result<(), Error> {
|
||||
self.handle.claim_interface(self.led_interface_num)?;
|
||||
// Declared as a zoomy so that it is hidden
|
||||
let write = |message: &[u8]| {
|
||||
self.handle
|
||||
.write_control(0x21, 0x09, 0x035D, 0, message, Duration::new(0, 5))
|
||||
};
|
||||
|
||||
if !self.initialised {
|
||||
write(&LED_INIT1)?;
|
||||
write(LED_INIT2.as_bytes())?;
|
||||
write(&LED_INIT3)?;
|
||||
write(LED_INIT4.as_bytes())?;
|
||||
write(&LED_INIT5)?;
|
||||
}
|
||||
|
||||
for message in messages {
|
||||
println!("{:x?}", &message);
|
||||
write(message)?;
|
||||
write(&LED_SET)?;
|
||||
//write(&LED_APPLY)?;
|
||||
}
|
||||
|
||||
self.handle.release_interface(self.led_interface_num)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn aura_set_brightness(&mut self, brightness: u8) -> Result<(), Error> {
|
||||
let mut bright = LED_BRIGHT_BYTES.to_vec();
|
||||
bright[4] = brightness;
|
||||
let messages = [bright];
|
||||
self.aura_write_messages(&messages)
|
||||
}
|
||||
|
||||
pub fn aura_set_colour(&mut self, rgb: (u8, u8, u8)) -> Result<(), Error> {
|
||||
let mut colour = LED_BUILTIN.to_vec();
|
||||
colour[3] = 0; // static
|
||||
colour[4] = rgb.0;
|
||||
colour[5] = rgb.1;
|
||||
colour[6] = rgb.2;
|
||||
let messages = [colour];
|
||||
self.aura_write_messages(&messages)
|
||||
}
|
||||
|
||||
pub fn aura_set_rainbow(&mut self, speed: u8) -> Result<(), Error> {
|
||||
let mut rainbow = LED_BUILTIN.to_vec();
|
||||
rainbow[3] = 3;
|
||||
rainbow[7] = speed;
|
||||
let messages = [rainbow];
|
||||
self.aura_write_messages(&messages)
|
||||
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::ParseMode => "incorrect mode specified",
|
||||
AuraError::ParseColour => "could not parse colour",
|
||||
AuraError::ParseSpeed => "could not parse speed",
|
||||
AuraError::ParseDirection => "could not parse direction",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq)]
|
||||
pub struct Colour(u8, u8, u8);
|
||||
|
||||
impl FromStr for Colour {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.len() < 6 {
|
||||
return Err(AuraError::ParseColour);
|
||||
}
|
||||
let r = u8::from_str_radix(&s[0..2], 16).or(Err(AuraError::ParseColour))?;
|
||||
let g = u8::from_str_radix(&s[2..4], 16).or(Err(AuraError::ParseColour))?;
|
||||
let b = u8::from_str_radix(&s[4..6], 16).or(Err(AuraError::ParseColour))?;
|
||||
Ok(Colour(r, g, b))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Speed {
|
||||
Slow = 0xe1,
|
||||
Medium = 0xeb,
|
||||
Fast = 0xf5,
|
||||
}
|
||||
impl Default for Speed {
|
||||
fn default() -> Self {
|
||||
Speed::Slow
|
||||
}
|
||||
}
|
||||
impl FromStr for Speed {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"slow" => Ok(Speed::Slow),
|
||||
"medium" => Ok(Speed::Medium),
|
||||
"fast" => Ok(Speed::Fast),
|
||||
_ => Err(AuraError::ParseSpeed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for Rainbow mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Direction {
|
||||
Right,
|
||||
Left,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
impl Default for Direction {
|
||||
fn default() -> Self {
|
||||
Direction::Right
|
||||
}
|
||||
}
|
||||
impl FromStr for Direction {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"right" => Ok(Direction::Right),
|
||||
"up" => Ok(Direction::Up),
|
||||
"down" => Ok(Direction::Down),
|
||||
"left" => Ok(Direction::Left),
|
||||
_ => Err(AuraError::ParseDirection),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Byte value for setting the built-in mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ModeByte {
|
||||
Stable, // colour1
|
||||
Breathe, // colour1, colour2, speed
|
||||
Cycle, // speed
|
||||
Rainbow, // speed, direction
|
||||
Rain, // colour1, speed
|
||||
Random, // speed
|
||||
Highlight, // colour1, speed
|
||||
Laser, // colour1, speed
|
||||
Ripple, // colour1, speed
|
||||
Off, // none
|
||||
Pulse, // colour1
|
||||
LineRace, // colour1
|
||||
WideLineRace, // colour1
|
||||
}
|
||||
impl Default for ModeByte {
|
||||
fn default() -> Self {
|
||||
ModeByte::Stable
|
||||
}
|
||||
}
|
||||
impl FromStr for ModeByte {
|
||||
type Err = AuraError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"stable" => Ok(ModeByte::Stable),
|
||||
"breathe" => Ok(ModeByte::Breathe),
|
||||
"cycle" => Ok(ModeByte::Cycle),
|
||||
"rainbow" => Ok(ModeByte::Rainbow),
|
||||
"rain" => Ok(ModeByte::Rain),
|
||||
"random" => Ok(ModeByte::Random),
|
||||
"highlight" => Ok(ModeByte::Highlight),
|
||||
"laser" => Ok(ModeByte::Laser),
|
||||
"ripple" => Ok(ModeByte::Ripple),
|
||||
"off" => Ok(ModeByte::Off),
|
||||
"pulse" => Ok(ModeByte::Pulse),
|
||||
"linerace" => Ok(ModeByte::LineRace),
|
||||
"widelinerace" => Ok(ModeByte::WideLineRace),
|
||||
_ => Err(AuraError::ParseMode),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Options)]
|
||||
pub struct BuiltInMode {
|
||||
#[options(help = "selects from the built-in keyboard modes")]
|
||||
mode: ModeByte,
|
||||
#[options(help = "set the first colour if a mode uses it, must be in hex: ffffff")]
|
||||
colour1: Colour,
|
||||
#[options(help = "set the second colour if a mode uses it, must be in hex: ffffff")]
|
||||
colour2: Colour,
|
||||
#[options(help = "set the speed of an effect if a mode uses it")]
|
||||
speed: Speed,
|
||||
#[options(help = "set the direction of an effect if a mode uses it")]
|
||||
direction: Direction,
|
||||
}
|
||||
|
||||
impl Default for BuiltInMode {
|
||||
fn default() -> BuiltInMode {
|
||||
BuiltInMode {
|
||||
mode: ModeByte::Stable,
|
||||
colour1: Colour(0xff, 0x00, 0x00),
|
||||
colour2: Colour(0x00, 0x00, 0x00),
|
||||
speed: Speed::Slow,
|
||||
direction: Direction::Right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Packet Data:
|
||||
///
|
||||
/// ```
|
||||
/// | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12| 13|
|
||||
/// |---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
/// |5d |b3 |03 |00 |ff |00 |00 |00 |00 |00 |00 |ff |00 |
|
||||
/// ```
|
||||
///
|
||||
/// Bytes 1 and 2 should always be 5d, b3
|
||||
///
|
||||
/// Byte 3 sets the mode type:
|
||||
/// - 00 = static
|
||||
/// - 01 = breathe (can set two colours)
|
||||
/// - 02 = cycle (through all colours)
|
||||
/// - 03 = rainbow
|
||||
/// - 04 = rain
|
||||
/// - 05 = random keys, red, white, turquoise
|
||||
/// - 06 = pressed keys light up and fade
|
||||
/// - 07 = pressed key emits laser
|
||||
/// - 08 = pressed key emits water ripple
|
||||
/// - 09 = off
|
||||
/// - 0a fast pulse (no speed setting)
|
||||
/// - 0b vertical line racing to right (no speed setting)
|
||||
/// - 0c wider vertical line racing to right (no speed setting)
|
||||
///
|
||||
/// Bytes 4, 5, 6 are Red, Green, Blue
|
||||
///
|
||||
/// Byte 7 sets speed from
|
||||
/// - 0x00 = Off
|
||||
/// - 0xe1 = Slow
|
||||
/// - 0xeb = Medium
|
||||
/// - 0xf5 = Fast
|
||||
///
|
||||
/// Byte 8 sets rainbow direction:
|
||||
/// - 0x00 = rightwards
|
||||
/// - 0x01 = leftwards
|
||||
/// - 0x02 = upwards
|
||||
/// - 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]);
|
||||
|
||||
impl From<BuiltInMode> for ModeMessage {
|
||||
fn from(mode: BuiltInMode) -> Self {
|
||||
let mut msg = [0u8; LED_MSG_LEN];
|
||||
msg[0] = 0x5d;
|
||||
msg[1] = 0xb3;
|
||||
msg[3] = mode.mode as u8;
|
||||
msg[4] = mode.colour1.0;
|
||||
msg[5] = mode.colour1.1;
|
||||
msg[6] = mode.colour1.2;
|
||||
msg[7] = mode.speed as u8;
|
||||
msg[8] = mode.direction as u8;
|
||||
msg[10] = mode.colour2.0;
|
||||
msg[11] = mode.colour2.1;
|
||||
msg[12] = mode.colour2.2;
|
||||
|
||||
ModeMessage(msg)
|
||||
}
|
||||
}
|
||||
|
||||
143
src/core.rs
Normal file
143
src/core.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use crate::aura::ModeMessage;
|
||||
use rusb::{DeviceHandle, Error};
|
||||
use std::time::Duration;
|
||||
|
||||
pub const LED_MSG_LEN: usize = 17;
|
||||
pub static LED_SPEED_BYTES: [u8; 3] = [0xe1, 0xeb, 0xf5]; // maps to 1, 2, 3
|
||||
static LED_BRIGHT_BYTES: [u8; 5] = [0x5a, 0xba, 0xc5, 0xc4, 0]; // Index 4 = set brightness
|
||||
static LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||
static LED_INIT2: &'static str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||
static LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
static LED_INIT4: &'static str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||
static LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
|
||||
static LED_BUILTIN: [u8; 13] = [
|
||||
0x5d, 0xb3, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
|
||||
];
|
||||
|
||||
// Only these two packets must be 17 bytes
|
||||
static LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 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];
|
||||
|
||||
// bytes 0,1 set mode
|
||||
// bytes 3,4,5 set to on,
|
||||
// byte 6 increments (starts at 0x00, continues 0x10 to 0xA0) 0-10 << 4
|
||||
// byte 7 resets (stays on 10 until byte6 == 0xA0 then flips to 08 in same packet as 0xA0)
|
||||
// bytes 8-57 are bitfield for keys
|
||||
static LED_SPECIAL: [u8; 64] = [
|
||||
0x5d, 0xbc, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
|
||||
/// ROG device controller
|
||||
///
|
||||
/// For the GX502GW the LED setup sequence looks like:
|
||||
///
|
||||
/// -` LED_INIT1`
|
||||
/// - `LED_INIT3`
|
||||
/// - `LED_INIT4`
|
||||
/// - `LED_INIT2`
|
||||
/// - `LED_INIT4`
|
||||
pub struct RogCore {
|
||||
handle: DeviceHandle<rusb::GlobalContext>,
|
||||
initialised: bool,
|
||||
led_interface_num: u8,
|
||||
keys_interface_num: u8,
|
||||
}
|
||||
|
||||
impl RogCore {
|
||||
pub fn new() -> Result<RogCore, Error> {
|
||||
let mut handle = RogCore::get_device(0x0B05, 0x1866)?;
|
||||
handle.set_active_configuration(0).unwrap_or(());
|
||||
|
||||
let config = handle.device().config_descriptor(0).unwrap();
|
||||
// Interface with outputs
|
||||
let mut keys_interface_num = 0;
|
||||
let mut led_interface_num = 0;
|
||||
for iface in config.interfaces() {
|
||||
for desc in iface.descriptors() {
|
||||
for endpoint in desc.endpoint_descriptors() {
|
||||
if endpoint.address() == 0x83 {
|
||||
keys_interface_num = desc.interface_number();
|
||||
} else if endpoint.address() == 0x81 {
|
||||
led_interface_num = desc.interface_number();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handle.set_auto_detach_kernel_driver(true).unwrap();
|
||||
handle.set_auto_detach_kernel_driver(true).unwrap();
|
||||
|
||||
// let iface_out = config
|
||||
// .interfaces()
|
||||
// .nth(keys_interface_num as usize)
|
||||
// .unwrap();
|
||||
// let iface_led = config.interfaces().nth(led_interface_num as usize).unwrap();
|
||||
|
||||
//handle.claim_interface(iface_out.number()).unwrap();
|
||||
//handle.claim_interface(iface_led.number()).unwrap();
|
||||
|
||||
Ok(RogCore {
|
||||
handle,
|
||||
initialised: false,
|
||||
led_interface_num,
|
||||
keys_interface_num,
|
||||
})
|
||||
}
|
||||
|
||||
fn get_device(vendor: u16, product: u16) -> Result<DeviceHandle<rusb::GlobalContext>, Error> {
|
||||
for device in rusb::devices().unwrap().iter() {
|
||||
let device_desc = device.device_descriptor().unwrap();
|
||||
if device_desc.vendor_id() == vendor && device_desc.product_id() == product {
|
||||
return device.open();
|
||||
}
|
||||
}
|
||||
Err(Error::NoDevice)
|
||||
}
|
||||
|
||||
fn aura_write_messages(&mut self, messages: &[[u8; LED_MSG_LEN]]) -> Result<(), Error> {
|
||||
self.handle.claim_interface(self.led_interface_num)?;
|
||||
// Declared as a zoomy so that it is hidden
|
||||
let write = |message: &[u8]| {
|
||||
self.handle
|
||||
.write_control(0x21, 0x09, 0x035D, 0, message, Duration::new(0, 5))
|
||||
};
|
||||
|
||||
if !self.initialised {
|
||||
write(&LED_INIT1)?;
|
||||
write(LED_INIT2.as_bytes())?;
|
||||
write(&LED_INIT3)?;
|
||||
write(LED_INIT4.as_bytes())?;
|
||||
write(&LED_INIT5)?;
|
||||
}
|
||||
|
||||
for message in messages {
|
||||
println!("{:x?}", &message);
|
||||
write(message)?;
|
||||
write(&LED_SET)?;
|
||||
//write(&LED_APPLY)?;
|
||||
}
|
||||
|
||||
self.handle.release_interface(self.led_interface_num)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn aura_set_brightness(&mut self, brightness: u8) -> Result<(), 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)
|
||||
}
|
||||
|
||||
pub fn aura_set_mode(&mut self, mode: ModeMessage) -> Result<(), Error> {
|
||||
let messages = [mode.0];
|
||||
self.aura_write_messages(&messages)
|
||||
}
|
||||
}
|
||||
55
src/main.rs
55
src/main.rs
@@ -1,12 +1,57 @@
|
||||
extern crate rusb;
|
||||
mod aura;
|
||||
mod core;
|
||||
|
||||
use aura::RogCore;
|
||||
use crate::aura::{BuiltInMode, ModeMessage};
|
||||
use crate::core::RogCore;
|
||||
use gumdrop::{Options, ParsingStyle};
|
||||
use std::env;
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
struct CLIStart {
|
||||
#[options(command, required)]
|
||||
command: Option<Command>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
enum Command {
|
||||
#[options(help = "show help for a command (eg: help aura)")]
|
||||
Help(FreeOptions),
|
||||
#[options(help = "Set the keyboard lighting from built-in modes")]
|
||||
LedMode(BuiltInMode),
|
||||
}
|
||||
|
||||
#[derive(Debug, Options)]
|
||||
struct FreeOptions {
|
||||
#[options(free)]
|
||||
free: Vec<String>,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut core = RogCore::new()?;
|
||||
core.aura_set_brightness(3)?;
|
||||
core.aura_set_colour((0xff, 0x00, 0x00))?;
|
||||
let args: Vec<String> = env::args().collect();
|
||||
match CLIStart::parse_args(&args[1..], ParsingStyle::AllOptions) {
|
||||
Ok(okk) => {
|
||||
dbg!(&okk);
|
||||
match okk.command {
|
||||
Some(Command::Help(help)) => {
|
||||
if help.free.contains(&"aura".to_string()) {
|
||||
println!("\n{}", BuiltInMode::usage())
|
||||
}
|
||||
}
|
||||
Some(Command::LedMode(aura)) => {
|
||||
let mut core = RogCore::new()?;
|
||||
let mode = ModeMessage::from(aura);
|
||||
core.aura_set_mode(mode)?;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
println!("\n{}", err);
|
||||
println!("\nUsage:\n{}", Command::usage());
|
||||
}
|
||||
}
|
||||
|
||||
//core.aura_set_brightness(3)?;
|
||||
|
||||
// core.test_builtins(aura::LED_SPEED_BYTES[2])?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user