mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Begin rog-aura crate
This commit is contained in:
371
rog-aura/src/aura_modes.rs
Normal file
371
rog-aura/src/aura_modes.rs
Normal file
@@ -0,0 +1,371 @@
|
||||
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::str::FromStr;
|
||||
use zvariant_derive::Type;
|
||||
|
||||
use crate::{LED_MSG_LEN, error::Error};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
||||
pub enum LedBrightness {
|
||||
Off,
|
||||
Low,
|
||||
Med,
|
||||
High,
|
||||
}
|
||||
|
||||
impl LedBrightness {
|
||||
pub fn as_char_code(&self) -> u8 {
|
||||
std::char::from_digit(*self as u32, 10).unwrap() as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for LedBrightness {
|
||||
fn from(bright: u32) -> Self {
|
||||
match bright {
|
||||
0 => LedBrightness::Off,
|
||||
1 => LedBrightness::Low,
|
||||
2 => LedBrightness::Med,
|
||||
3 => LedBrightness::High,
|
||||
_ => LedBrightness::Med,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Copy, Deserialize, Serialize, Type)]
|
||||
pub struct Colour(pub u8, pub u8, pub u8);
|
||||
|
||||
impl Default for Colour {
|
||||
fn default() -> Self {
|
||||
Colour(166, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Colour {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if s.len() < 6 {
|
||||
return Err(Error::ParseColour);
|
||||
}
|
||||
let r = u8::from_str_radix(&s[0..2], 16).or(Err(Error::ParseColour))?;
|
||||
let g = u8::from_str_radix(&s[2..4], 16).or(Err(Error::ParseColour))?;
|
||||
let b = u8::from_str_radix(&s[4..6], 16).or(Err(Error::ParseColour))?;
|
||||
Ok(Colour(r, g, b))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
||||
pub enum Speed {
|
||||
Low = 0xe1,
|
||||
Med = 0xeb,
|
||||
High = 0xf5,
|
||||
}
|
||||
impl Default for Speed {
|
||||
fn default() -> Self {
|
||||
Speed::Med
|
||||
}
|
||||
}
|
||||
impl FromStr for Speed {
|
||||
type Err = Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"low" => Ok(Speed::Low),
|
||||
"med" => Ok(Speed::Med),
|
||||
"high" => Ok(Speed::High),
|
||||
_ => Err(Error::ParseSpeed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Used for Rainbow mode.
|
||||
///
|
||||
/// Enum corresponds to the required integer value
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Deserialize, Serialize, Type)]
|
||||
pub enum Direction {
|
||||
Right,
|
||||
Left,
|
||||
Up,
|
||||
Down,
|
||||
}
|
||||
impl Default for Direction {
|
||||
fn default() -> Self {
|
||||
Direction::Right
|
||||
}
|
||||
}
|
||||
impl FromStr for Direction {
|
||||
type Err = Error;
|
||||
|
||||
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(Error::ParseDirection),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
Debug, Type, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy, Deserialize, Serialize,
|
||||
)]
|
||||
pub enum AuraModeNum {
|
||||
Static = 0,
|
||||
Breathe = 1,
|
||||
Strobe = 2,
|
||||
Rainbow = 3,
|
||||
Star = 4,
|
||||
Rain = 5,
|
||||
Highlight = 6,
|
||||
Laser = 7,
|
||||
Ripple = 8,
|
||||
Pulse = 10,
|
||||
Comet = 11,
|
||||
Flash = 12,
|
||||
}
|
||||
|
||||
impl From<&AuraModeNum> for &str {
|
||||
fn from(mode: &AuraModeNum) -> Self {
|
||||
match mode {
|
||||
AuraModeNum::Static => "Static",
|
||||
AuraModeNum::Breathe => "Breathing",
|
||||
AuraModeNum::Strobe => "Strobing",
|
||||
AuraModeNum::Rainbow => "Rainbow",
|
||||
AuraModeNum::Star => "Stars",
|
||||
AuraModeNum::Rain => "Rain",
|
||||
AuraModeNum::Highlight => "Keypress Highlight",
|
||||
AuraModeNum::Laser => "Keypress Laser",
|
||||
AuraModeNum::Ripple => "Keypress Ripple",
|
||||
AuraModeNum::Pulse => "Pulse",
|
||||
AuraModeNum::Comet => "Comet",
|
||||
AuraModeNum::Flash => "Flash",
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<&str> for AuraModeNum {
|
||||
fn from(mode: &str) -> Self {
|
||||
match mode {
|
||||
"Static" => AuraModeNum::Static,
|
||||
"Breathing" => AuraModeNum::Breathe,
|
||||
"Strobing" => AuraModeNum::Strobe,
|
||||
"Rainbow" => AuraModeNum::Rainbow,
|
||||
"Stars" => AuraModeNum::Star,
|
||||
"Rain" => AuraModeNum::Rain,
|
||||
"Keypress Highlight" => AuraModeNum::Highlight,
|
||||
"Keypress Laser" => AuraModeNum::Laser,
|
||||
"Keypress Ripple" => AuraModeNum::Ripple,
|
||||
"Pulse" => AuraModeNum::Pulse,
|
||||
"Comet" => AuraModeNum::Comet,
|
||||
"Flash" => AuraModeNum::Flash,
|
||||
_ => AuraModeNum::Static,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for AuraModeNum {
|
||||
fn from(mode: u8) -> Self {
|
||||
match mode {
|
||||
0 => AuraModeNum::Static,
|
||||
1 => AuraModeNum::Breathe,
|
||||
2 => AuraModeNum::Strobe,
|
||||
3 => AuraModeNum::Rainbow,
|
||||
4 => AuraModeNum::Star,
|
||||
5 => AuraModeNum::Rain,
|
||||
6 => AuraModeNum::Highlight,
|
||||
7 => AuraModeNum::Laser,
|
||||
8 => AuraModeNum::Ripple,
|
||||
10 => AuraModeNum::Pulse,
|
||||
11 => AuraModeNum::Comet,
|
||||
12 => AuraModeNum::Flash,
|
||||
_ => AuraModeNum::Static,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct AuraMultiZone {
|
||||
static_: [AuraEffect; 4],
|
||||
breathe: [AuraEffect; 4],
|
||||
}
|
||||
|
||||
impl AuraMultiZone {
|
||||
pub fn set(&mut self, effect: AuraEffect) {
|
||||
if effect.mode == AuraModeNum::Static {
|
||||
match effect.zone {
|
||||
AuraZone::None => {}
|
||||
AuraZone::One => self.static_[0] = effect,
|
||||
AuraZone::Two => self.static_[1] = effect,
|
||||
AuraZone::Three => self.static_[2] = effect,
|
||||
AuraZone::Four => self.static_[3] = effect,
|
||||
}
|
||||
} else if effect.mode == AuraModeNum::Breathe {
|
||||
match effect.zone {
|
||||
AuraZone::None => {}
|
||||
AuraZone::One => self.breathe[0] = effect,
|
||||
AuraZone::Two => self.breathe[1] = effect,
|
||||
AuraZone::Three => self.breathe[2] = effect,
|
||||
AuraZone::Four => self.breathe[3] = effect,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn static_(&self) -> &[AuraEffect; 4] {
|
||||
&self.static_
|
||||
}
|
||||
|
||||
pub fn breathe(&self) -> &[AuraEffect; 4] {
|
||||
&self.breathe
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AuraMultiZone {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
static_: [
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Static,
|
||||
zone: AuraZone::One,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Static,
|
||||
zone: AuraZone::Two,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Static,
|
||||
zone: AuraZone::Three,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Static,
|
||||
zone: AuraZone::Four,
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
breathe: [
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Breathe,
|
||||
zone: AuraZone::One,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Breathe,
|
||||
zone: AuraZone::Two,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Breathe,
|
||||
zone: AuraZone::Three,
|
||||
..Default::default()
|
||||
},
|
||||
AuraEffect {
|
||||
mode: AuraModeNum::Breathe,
|
||||
zone: AuraZone::Four,
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Base effects have no zoning, while multizone is 1-4
|
||||
#[derive(Debug, Type, Copy, Clone, PartialEq, Deserialize, Serialize)]
|
||||
pub enum AuraZone {
|
||||
None,
|
||||
One,
|
||||
Two,
|
||||
Three,
|
||||
Four,
|
||||
}
|
||||
|
||||
/// Default factory modes structure
|
||||
#[derive(Debug, Type, Clone, Deserialize, Serialize)]
|
||||
pub struct AuraEffect {
|
||||
/// The effect type
|
||||
pub mode: AuraModeNum,
|
||||
/// `AuraZone::None` for no zone or zoneless keyboards
|
||||
pub zone: AuraZone,
|
||||
/// Primary colour for all modes
|
||||
pub colour1: Colour,
|
||||
/// Secondary colour in some modes like Breathing or Stars
|
||||
pub colour2: Colour,
|
||||
/// One of three speeds for modes that support speed (most that animate)
|
||||
pub speed: Speed,
|
||||
/// Up, down, left, right. Only Rainbow mode seems to use this
|
||||
pub direction: Direction,
|
||||
}
|
||||
|
||||
impl AuraEffect {
|
||||
pub fn mode(&self) -> &AuraModeNum {
|
||||
&self.mode
|
||||
}
|
||||
|
||||
pub fn mode_name(&self) -> String {
|
||||
(<&str>::from(&self.mode)).to_string()
|
||||
}
|
||||
|
||||
pub fn mode_num(&self) -> u8 {
|
||||
self.mode as u8
|
||||
}
|
||||
|
||||
pub fn default_with_mode(mode: AuraModeNum) -> Self {
|
||||
Self {
|
||||
mode,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn zone(&self) -> AuraZone {
|
||||
self.zone
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AuraEffect {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: AuraModeNum::Static,
|
||||
zone: AuraZone::None,
|
||||
colour1: Colour(166, 0, 0),
|
||||
colour2: Colour(0, 0, 0),
|
||||
speed: Speed::Med,
|
||||
direction: Direction::Right,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses `AuraEffect` in to packet data for writing to the USB interface
|
||||
///
|
||||
/// Byte structure:
|
||||
/// ```ignore
|
||||
/// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10| 11| 12|
|
||||
/// |---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||
/// |5d |b3 |00 |03 |ff |00 |00 |00 |00 |00 |00 |ff |00 |
|
||||
/// ```
|
||||
impl From<&AuraEffect> for [u8; LED_MSG_LEN] {
|
||||
fn from(aura: &AuraEffect) -> Self {
|
||||
let mut msg = [0u8; LED_MSG_LEN];
|
||||
msg[0] = 0x5d;
|
||||
msg[1] = 0xb3;
|
||||
msg[2] = aura.zone as u8;
|
||||
msg[3] = aura.mode as u8;
|
||||
msg[4] = aura.colour1.0;
|
||||
msg[5] = aura.colour1.1;
|
||||
msg[6] = aura.colour1.2;
|
||||
msg[7] = aura.speed as u8;
|
||||
msg[8] = aura.direction as u8;
|
||||
msg[10] = aura.colour2.0;
|
||||
msg[11] = aura.colour2.1;
|
||||
msg[12] = aura.colour2.2;
|
||||
|
||||
msg
|
||||
}
|
||||
}
|
||||
456
rog-aura/src/aura_perkey.rs
Normal file
456
rog-aura/src/aura_perkey.rs
Normal file
@@ -0,0 +1,456 @@
|
||||
/// A `KeyColourArray` contains all data to change the full set of keyboard
|
||||
/// key colours individually.
|
||||
///
|
||||
/// Each row of the internal array is a full HID packet that can be sent
|
||||
/// to the keyboard EC. One row controls one group of keys, these keys are not
|
||||
/// necessarily all on the same row of the keyboard, with some splitting between
|
||||
/// two rows.
|
||||
#[derive(Clone)]
|
||||
pub struct KeyColourArray([[u8; 64]; 11]);
|
||||
impl Default for KeyColourArray {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
impl KeyColourArray {
|
||||
pub fn new() -> Self {
|
||||
let mut set = [[0u8; 64]; 11];
|
||||
for (count, row) in set.iter_mut().enumerate() {
|
||||
row[0] = 0x5d; // Report ID
|
||||
row[1] = 0xbc; // Mode = custom??, 0xb3 is builtin
|
||||
row[2] = 0x00;
|
||||
row[3] = 0x01; // ??
|
||||
row[4] = 0x01; // ??, 4,5,6 are normally RGB for builtin mode colours
|
||||
row[5] = 0x01; // ??
|
||||
row[6] = (count as u8) << 4; // Key group
|
||||
if count == 10 {
|
||||
row[7] = 0x08; // 0b00001000
|
||||
} else {
|
||||
row[7] = 0x10; // 0b00010000 addressing? flips for group a0
|
||||
}
|
||||
row[8] = 0x00;
|
||||
}
|
||||
KeyColourArray(set)
|
||||
}
|
||||
|
||||
/// Initialise and clear the keyboard for custom effects
|
||||
#[inline]
|
||||
pub const fn get_init_msg() -> [u8; 64] {
|
||||
let mut init = [0u8; 64];
|
||||
init[0] = 0x5d; // Report ID
|
||||
init[1] = 0xbc; // Mode = custom??, 0xb3 is builtin
|
||||
init
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set(&mut self, key: Key, r: u8, g: u8, b: u8) {
|
||||
if let Some((rr, gg, bb)) = self.key(key) {
|
||||
*rr = r;
|
||||
*gg = g;
|
||||
*bb = b;
|
||||
}
|
||||
}
|
||||
|
||||
/// Indexes in to `KeyColourArray` at the correct row and column
|
||||
/// to set a series of three bytes to the chosen R,G,B values
|
||||
pub fn key(&mut self, key: Key) -> Option<(&mut u8, &mut u8, &mut u8)> {
|
||||
// Tuples are indexes in to array
|
||||
let (row, col) = match key {
|
||||
Key::VolDown => (0, 15),
|
||||
Key::VolUp => (0, 18),
|
||||
Key::MicMute => (0, 21),
|
||||
Key::Rog => (0, 24),
|
||||
//
|
||||
Key::Esc => (1, 24),
|
||||
Key::F1 => (1, 30),
|
||||
Key::F2 => (1, 33),
|
||||
Key::F3 => (1, 36),
|
||||
Key::F4 => (1, 39),
|
||||
Key::F5 => (1, 45),
|
||||
Key::F6 => (1, 48),
|
||||
Key::F7 => (1, 51),
|
||||
Key::F8 => (1, 54),
|
||||
//
|
||||
Key::F9 => (2, 12),
|
||||
Key::F10 => (2, 15),
|
||||
Key::F11 => (2, 18),
|
||||
Key::F12 => (2, 21),
|
||||
Key::Del => (2, 24),
|
||||
Key::Tilde => (2, 39),
|
||||
Key::N1 => (2, 42),
|
||||
Key::N2 => (2, 45),
|
||||
Key::N3 => (2, 48),
|
||||
Key::N4 => (2, 51),
|
||||
Key::N5 => (2, 54),
|
||||
//
|
||||
Key::N6 => (3, 9),
|
||||
Key::N7 => (3, 12),
|
||||
Key::N8 => (3, 15),
|
||||
Key::N9 => (3, 18),
|
||||
Key::N0 => (3, 21),
|
||||
Key::Hyphen => (3, 24),
|
||||
Key::Equals => (3, 27),
|
||||
Key::BkSpc1 => (3, 30),
|
||||
Key::BkSpc2 => (3, 33),
|
||||
Key::BkSpc3 => (3, 36),
|
||||
Key::Home => (3, 39),
|
||||
Key::Tab => (3, 54),
|
||||
//
|
||||
Key::Q => (4, 9),
|
||||
Key::W => (4, 12),
|
||||
Key::E => (4, 15),
|
||||
Key::R => (4, 18),
|
||||
Key::T => (4, 21),
|
||||
Key::Y => (4, 24),
|
||||
Key::U => (4, 27),
|
||||
Key::I => (4, 30),
|
||||
Key::O => (4, 33),
|
||||
Key::P => (4, 36),
|
||||
Key::LBracket => (4, 39),
|
||||
Key::RBracket => (4, 42),
|
||||
Key::BackSlash => (4, 45),
|
||||
Key::PgUp => (4, 54),
|
||||
//
|
||||
Key::Caps => (5, 21),
|
||||
Key::A => (5, 24),
|
||||
Key::S => (5, 27),
|
||||
Key::D => (5, 30),
|
||||
Key::F => (5, 33),
|
||||
Key::G => (5, 36),
|
||||
Key::H => (5, 39),
|
||||
Key::J => (5, 42),
|
||||
Key::K => (5, 45),
|
||||
Key::L => (5, 48),
|
||||
Key::SemiColon => (5, 51),
|
||||
Key::Quote => (5, 54),
|
||||
//
|
||||
Key::Ret1 => (6, 12),
|
||||
Key::Ret2 => (6, 15),
|
||||
Key::Ret3 => (6, 18),
|
||||
Key::PgDn => (6, 21),
|
||||
Key::LShift => (6, 36),
|
||||
Key::Z => (6, 42),
|
||||
Key::X => (6, 45),
|
||||
Key::C => (6, 48),
|
||||
Key::V => (6, 51),
|
||||
Key::B => (6, 54),
|
||||
//
|
||||
Key::N => (7, 9),
|
||||
Key::M => (7, 12),
|
||||
Key::Comma => (7, 15),
|
||||
Key::Period => (7, 18),
|
||||
Key::FwdSlash => (7, 21),
|
||||
Key::Rshift1 => (7, 27),
|
||||
Key::Rshift2 => (7, 30),
|
||||
Key::Rshift3 => (7, 33),
|
||||
Key::End => (7, 36),
|
||||
Key::LCtrl => (7, 51),
|
||||
Key::LFn => (7, 54),
|
||||
//
|
||||
Key::Meta => (8, 9),
|
||||
Key::LAlt => (8, 12),
|
||||
Key::Space1 => (8, 15),
|
||||
Key::Space2 => (8, 18),
|
||||
Key::Space3 => (8, 21),
|
||||
Key::Space4 => (8, 24),
|
||||
Key::RAlt => (8, 30),
|
||||
Key::PrtSc => (8, 33),
|
||||
Key::RCtrl => (8, 36),
|
||||
Key::Up => (8, 42),
|
||||
Key::RFn => (8, 51),
|
||||
//
|
||||
Key::Left => (9, 54),
|
||||
//
|
||||
Key::Down => (10, 9),
|
||||
Key::Right => (10, 12),
|
||||
Key::None => return None,
|
||||
};
|
||||
// LOLOLOLOLOLOLOL! Look it's safe okay
|
||||
unsafe {
|
||||
Some((
|
||||
&mut *(&mut self.0[row][col] as *mut u8),
|
||||
&mut *(&mut self.0[row][col + 1] as *mut u8),
|
||||
&mut *(&mut self.0[row][col + 2] as *mut u8),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get(&self) -> &[[u8; 64]; 11] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Copy, Clone)]
|
||||
pub enum Key {
|
||||
VolUp,
|
||||
VolDown,
|
||||
MicMute,
|
||||
Rog,
|
||||
Esc,
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
F7,
|
||||
F8,
|
||||
F9,
|
||||
F10,
|
||||
F11,
|
||||
F12,
|
||||
Del,
|
||||
Tilde,
|
||||
N1,
|
||||
N2,
|
||||
N3,
|
||||
N4,
|
||||
N5,
|
||||
N6,
|
||||
N7,
|
||||
N8,
|
||||
N9,
|
||||
N0,
|
||||
Hyphen,
|
||||
Equals,
|
||||
BkSpc1,
|
||||
BkSpc2,
|
||||
BkSpc3,
|
||||
Home,
|
||||
Tab,
|
||||
Q,
|
||||
W,
|
||||
E,
|
||||
R,
|
||||
T,
|
||||
Y,
|
||||
U,
|
||||
I,
|
||||
O,
|
||||
P,
|
||||
LBracket,
|
||||
RBracket,
|
||||
BackSlash,
|
||||
PgUp,
|
||||
Caps,
|
||||
A,
|
||||
S,
|
||||
D,
|
||||
F,
|
||||
G,
|
||||
H,
|
||||
J,
|
||||
K,
|
||||
L,
|
||||
SemiColon,
|
||||
Quote,
|
||||
Ret1,
|
||||
Ret2,
|
||||
Ret3,
|
||||
PgDn,
|
||||
LShift,
|
||||
Z,
|
||||
X,
|
||||
C,
|
||||
V,
|
||||
B,
|
||||
N,
|
||||
M,
|
||||
Comma,
|
||||
Period,
|
||||
FwdSlash,
|
||||
Rshift1,
|
||||
Rshift2,
|
||||
Rshift3,
|
||||
End,
|
||||
LCtrl,
|
||||
LFn,
|
||||
Meta,
|
||||
LAlt,
|
||||
Space1,
|
||||
Space2,
|
||||
Space3,
|
||||
Space4,
|
||||
RAlt,
|
||||
PrtSc,
|
||||
RCtrl,
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
RFn,
|
||||
None,
|
||||
}
|
||||
|
||||
pub trait KeyLayout {
|
||||
fn get_rows(&self) -> &Vec<[Key; 17]>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub struct GX502Layout(Vec<[Key; 17]>);
|
||||
|
||||
impl KeyLayout for GX502Layout {
|
||||
fn get_rows(&self) -> &Vec<[Key; 17]> {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for GX502Layout {
|
||||
fn default() -> Self {
|
||||
GX502Layout(vec![
|
||||
[
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::VolDown,
|
||||
Key::VolUp,
|
||||
Key::MicMute,
|
||||
Key::Rog,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
],
|
||||
[
|
||||
Key::Esc,
|
||||
Key::None,
|
||||
Key::F1,
|
||||
Key::F2,
|
||||
Key::F3,
|
||||
Key::F4,
|
||||
Key::None, // not sure which key to put here
|
||||
Key::F5,
|
||||
Key::F6,
|
||||
Key::F7,
|
||||
Key::F8,
|
||||
Key::F9,
|
||||
Key::F9,
|
||||
Key::F10,
|
||||
Key::F11,
|
||||
Key::F12,
|
||||
Key::Del,
|
||||
],
|
||||
[
|
||||
Key::Tilde,
|
||||
Key::N1,
|
||||
Key::N2,
|
||||
Key::N3,
|
||||
Key::N4,
|
||||
Key::N5,
|
||||
Key::N6,
|
||||
Key::N7,
|
||||
Key::N8,
|
||||
Key::N9,
|
||||
Key::N0,
|
||||
Key::Hyphen,
|
||||
Key::Equals,
|
||||
Key::BkSpc1,
|
||||
Key::BkSpc2,
|
||||
Key::BkSpc3,
|
||||
Key::Home,
|
||||
],
|
||||
[
|
||||
Key::Tab,
|
||||
Key::Q,
|
||||
Key::W,
|
||||
Key::E,
|
||||
Key::R,
|
||||
Key::T,
|
||||
Key::Y,
|
||||
Key::U,
|
||||
Key::I,
|
||||
Key::O,
|
||||
Key::P,
|
||||
Key::LBracket,
|
||||
Key::RBracket,
|
||||
Key::BackSlash,
|
||||
Key::BackSlash,
|
||||
Key::BackSlash,
|
||||
Key::PgUp,
|
||||
],
|
||||
[
|
||||
Key::Caps,
|
||||
Key::A,
|
||||
Key::S,
|
||||
Key::D,
|
||||
Key::F,
|
||||
Key::G,
|
||||
Key::H,
|
||||
Key::J,
|
||||
Key::K,
|
||||
Key::L,
|
||||
Key::SemiColon,
|
||||
Key::Quote,
|
||||
Key::Quote,
|
||||
Key::Ret1,
|
||||
Key::Ret2,
|
||||
Key::Ret3,
|
||||
Key::PgDn,
|
||||
],
|
||||
[
|
||||
Key::LShift,
|
||||
Key::LShift,
|
||||
Key::Z,
|
||||
Key::X,
|
||||
Key::C,
|
||||
Key::V,
|
||||
Key::B,
|
||||
Key::N,
|
||||
Key::M,
|
||||
Key::Comma,
|
||||
Key::Period,
|
||||
Key::FwdSlash,
|
||||
Key::FwdSlash,
|
||||
Key::Rshift1,
|
||||
Key::Rshift2,
|
||||
Key::Rshift3,
|
||||
Key::End,
|
||||
],
|
||||
[
|
||||
Key::LCtrl,
|
||||
Key::LFn,
|
||||
Key::Meta,
|
||||
Key::LAlt,
|
||||
Key::Space1,
|
||||
Key::Space2,
|
||||
Key::Space3,
|
||||
Key::Space4,
|
||||
Key::Space4,
|
||||
Key::RAlt,
|
||||
Key::PrtSc,
|
||||
Key::RCtrl,
|
||||
Key::RCtrl,
|
||||
Key::Left,
|
||||
Key::Up,
|
||||
Key::Right,
|
||||
Key::RFn,
|
||||
],
|
||||
[
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::None,
|
||||
Key::Left,
|
||||
Key::Down,
|
||||
Key::Right,
|
||||
Key::None,
|
||||
],
|
||||
])
|
||||
}
|
||||
}
|
||||
73
rog-aura/src/data.rs
Normal file
73
rog-aura/src/data.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
#[cfg(feature = "dbus")]
|
||||
use zvariant_derive::Type;
|
||||
|
||||
/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and `USB_PREFIX2`
|
||||
const BLOCK_START: usize = 7;
|
||||
/// *Not* inclusive, the byte before this is the final for each "pane"
|
||||
const BLOCK_END: usize = 634;
|
||||
/// Individual usable data length of each USB packet
|
||||
const PANE_LEN: usize = BLOCK_END - BLOCK_START;
|
||||
/// The length of usable data
|
||||
pub const ANIME_DATA_LEN: usize = PANE_LEN * 2;
|
||||
|
||||
const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
|
||||
const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
|
||||
|
||||
/// The minimal serializable data that can be transferred over wire types.
|
||||
/// Other data structures in `rog_anime` will convert to this.
|
||||
#[cfg_attr(feature = "dbus", derive(Type))]
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct AnimeDataBuffer(Vec<u8>);
|
||||
|
||||
impl Default for AnimeDataBuffer {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl AnimeDataBuffer {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
AnimeDataBuffer(vec![0u8; ANIME_DATA_LEN])
|
||||
}
|
||||
|
||||
/// Get the inner data buffer
|
||||
#[inline]
|
||||
pub fn get(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Get a mutable slice of the inner buffer
|
||||
#[inline]
|
||||
pub fn get_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Create from a vector of bytes
|
||||
///
|
||||
/// # Panics
|
||||
/// Will panic if the vector length is not `ANIME_DATA_LEN`
|
||||
#[inline]
|
||||
pub fn from_vec(input: Vec<u8>) -> Self {
|
||||
assert_eq!(input.len(), ANIME_DATA_LEN);
|
||||
Self(input)
|
||||
}
|
||||
}
|
||||
|
||||
/// The two packets to be written to USB
|
||||
pub type AnimePacketType = [[u8; 640]; 2];
|
||||
|
||||
impl From<AnimeDataBuffer> for AnimePacketType {
|
||||
#[inline]
|
||||
fn from(anime: AnimeDataBuffer) -> Self {
|
||||
assert!(anime.0.len() == ANIME_DATA_LEN);
|
||||
let mut buffers = [[0; 640]; 2];
|
||||
for (idx, chunk) in anime.0.as_slice().chunks(PANE_LEN).enumerate() {
|
||||
buffers[idx][BLOCK_START..BLOCK_END].copy_from_slice(chunk);
|
||||
}
|
||||
buffers[0][..7].copy_from_slice(&USB_PREFIX1);
|
||||
buffers[1][..7].copy_from_slice(&USB_PREFIX2);
|
||||
buffers
|
||||
}
|
||||
}
|
||||
26
rog-aura/src/error.rs
Normal file
26
rog-aura/src/error.rs
Normal file
@@ -0,0 +1,26 @@
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
ParseColour,
|
||||
ParseSpeed,
|
||||
ParseDirection,
|
||||
ParseBrightness,
|
||||
ParseAnime,
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
// This trait requires `fmt` with this exact signature.
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::ParseColour => write!(f, "Could not parse colour"),
|
||||
Error::ParseSpeed => write!(f, "Could not parse speed"),
|
||||
Error::ParseDirection => write!(f, "Could not parse direction"),
|
||||
Error::ParseBrightness => write!(f, "Could not parse brightness"),
|
||||
Error::ParseAnime => write!(f, "Could not parse anime"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {}
|
||||
21
rog-aura/src/lib.rs
Normal file
21
rog-aura/src/lib.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
/// The main data conversion for transfering in shortform over dbus or other,
|
||||
/// or writing directly to the USB device
|
||||
mod data;
|
||||
pub use data::*;
|
||||
|
||||
/// A container of images/grids/gifs/pauses which can be iterated over to generate
|
||||
/// cool effects
|
||||
mod sequencer;
|
||||
pub use sequencer::*;
|
||||
|
||||
mod aura_modes;
|
||||
pub use aura_modes::*;
|
||||
|
||||
mod aura_perkey;
|
||||
pub use aura_perkey::*;
|
||||
|
||||
pub mod usb;
|
||||
|
||||
pub mod error;
|
||||
|
||||
pub const LED_MSG_LEN: usize = 17;
|
||||
74
rog-aura/src/sequencer.rs
Normal file
74
rog-aura/src/sequencer.rs
Normal file
@@ -0,0 +1,74 @@
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
|
||||
/// All the possible AniMe actions that can be used. The enum is intended to be
|
||||
/// used in a array allowing the user to cycle through a series of actions.
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub enum ActionData {
|
||||
Static
|
||||
}
|
||||
|
||||
/// An optimised precomputed set of actions that the user can cycle through
|
||||
#[derive(Debug, Deserialize, Serialize, Default)]
|
||||
pub struct Sequences(Vec<ActionData>);
|
||||
|
||||
impl Sequences {
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
/// Use a base `AnimeAction` to generate the precomputed data and insert in to
|
||||
/// the run buffer
|
||||
#[inline]
|
||||
pub fn insert(&mut self, index: usize) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove an item at this position from the run buffer. If the `index` supplied
|
||||
/// is not in range then `None` is returned, otherwise the `ActionData` at that location
|
||||
/// is yeeted and returned.
|
||||
#[inline]
|
||||
pub fn remove_item(&mut self, index: usize) -> Option<ActionData> {
|
||||
if index < self.0.len() {
|
||||
return Some(self.0.remove(index));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> ActionIterator {
|
||||
ActionIterator {
|
||||
actions: &self,
|
||||
next_idx: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Iteractor helper for iterating over all the actions in `Sequences`
|
||||
pub struct ActionIterator<'a> {
|
||||
actions: &'a Sequences,
|
||||
next_idx: usize,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ActionIterator<'a> {
|
||||
type Item = &'a ActionData;
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<&'a ActionData> {
|
||||
if self.next_idx == self.actions.0.len() {
|
||||
self.next_idx = 0;
|
||||
return None;
|
||||
}
|
||||
|
||||
let current = self.next_idx;
|
||||
self.next_idx += 1;
|
||||
|
||||
Some(&self.actions.0[current])
|
||||
}
|
||||
}
|
||||
16
rog-aura/src/usb.rs
Normal file
16
rog-aura/src/usb.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
pub const LED_INIT1: [u8; 2] = [0x5d, 0xb9];
|
||||
pub const LED_INIT2: &str = "]ASUS Tech.Inc."; // ] == 0x5d
|
||||
pub const LED_INIT3: [u8; 6] = [0x5d, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
pub const LED_INIT4: &str = "^ASUS Tech.Inc."; // ^ == 0x5e
|
||||
pub const LED_INIT5: [u8; 6] = [0x5e, 0x05, 0x20, 0x31, 0, 0x08];
|
||||
|
||||
// Only these two packets must be 17 bytes
|
||||
pub const LED_APPLY: [u8; 17] = [0x5d, 0xb4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
pub const LED_SET: [u8; 17] = [0x5d, 0xb5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||
|
||||
/// Writes out the correct byte string for brightness
|
||||
pub const fn aura_brightness_bytes(brightness: u8) -> [u8; 17] {
|
||||
[
|
||||
0x5A, 0xBA, 0xC5, 0xC4, brightness, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user