mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-01-22 17:33:19 +01:00
695 lines
17 KiB
Rust
695 lines
17 KiB
Rust
use std::fmt::Display;
|
|
use std::str::FromStr;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
#[cfg(feature = "dbus")]
|
|
use zbus::zvariant::{OwnedValue, Type, Value};
|
|
|
|
use crate::error::Error;
|
|
use crate::AURA_LAPTOP_LED_MSG_LEN;
|
|
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
|
#[cfg_attr(
|
|
feature = "dbus",
|
|
derive(Type, Value, OwnedValue),
|
|
zvariant(signature = "u")
|
|
)]
|
|
pub enum LedBrightness {
|
|
Off = 0,
|
|
Low = 1,
|
|
#[default]
|
|
Med = 2,
|
|
High = 3
|
|
}
|
|
|
|
impl LedBrightness {
|
|
pub const fn next(&self) -> Self {
|
|
match self {
|
|
Self::Off => Self::Low,
|
|
Self::Low => Self::Med,
|
|
Self::Med => Self::High,
|
|
Self::High => Self::Off
|
|
}
|
|
}
|
|
|
|
pub const fn prev(&self) -> Self {
|
|
match self {
|
|
Self::Off => Self::High,
|
|
Self::Low => Self::Off,
|
|
Self::Med => Self::Low,
|
|
Self::High => Self::Med
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<u8> for LedBrightness {
|
|
fn from(bright: u8) -> Self {
|
|
match bright {
|
|
0 => LedBrightness::Off,
|
|
1 => LedBrightness::Low,
|
|
3 => LedBrightness::High,
|
|
_ => LedBrightness::Med
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<LedBrightness> for u8 {
|
|
fn from(l: LedBrightness) -> Self {
|
|
l as u8
|
|
}
|
|
}
|
|
|
|
impl From<LedBrightness> for i32 {
|
|
fn from(l: LedBrightness) -> Self {
|
|
l as i32
|
|
}
|
|
}
|
|
|
|
impl From<i32> for LedBrightness {
|
|
fn from(l: i32) -> Self {
|
|
match l {
|
|
0 => LedBrightness::Off,
|
|
1 => LedBrightness::Low,
|
|
2 => LedBrightness::Med,
|
|
3 => LedBrightness::High,
|
|
_ => LedBrightness::Med
|
|
}
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
|
|
#[derive(Debug, Clone, PartialEq, Eq, Copy, Deserialize, Serialize)]
|
|
pub struct Colour {
|
|
pub r: u8,
|
|
pub g: u8,
|
|
pub b: u8
|
|
}
|
|
|
|
impl Default for Colour {
|
|
fn default() -> Self {
|
|
Colour { r: 166, g: 0, b: 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 })
|
|
}
|
|
}
|
|
|
|
impl From<&[f32; 3]> for Colour {
|
|
fn from(c: &[f32; 3]) -> Self {
|
|
Self {
|
|
r: (255.0 * c[0]) as u8,
|
|
g: (255.0 * c[1]) as u8,
|
|
b: (255.0 * c[2]) as u8
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Colour> for [f32; 3] {
|
|
fn from(c: Colour) -> Self {
|
|
[
|
|
c.r as f32 / 255.0,
|
|
c.g as f32 / 255.0,
|
|
c.b as f32 / 255.0
|
|
]
|
|
}
|
|
}
|
|
|
|
impl From<&[u8; 3]> for Colour {
|
|
fn from(c: &[u8; 3]) -> Self {
|
|
Self {
|
|
r: c[0],
|
|
g: c[1],
|
|
b: c[2]
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Colour> for [u8; 3] {
|
|
fn from(c: Colour) -> Self {
|
|
[
|
|
c.r, c.g, c.b
|
|
]
|
|
}
|
|
}
|
|
|
|
#[cfg_attr(
|
|
feature = "dbus",
|
|
derive(Type, Value, OwnedValue),
|
|
zvariant(signature = "s")
|
|
)]
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub enum Speed {
|
|
Low = 0xe1,
|
|
#[default]
|
|
Med = 0xeb,
|
|
High = 0xf5
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for Speed {
|
|
fn from(value: i32) -> Self {
|
|
match value {
|
|
0 => Self::Low,
|
|
2 => Self::High,
|
|
_ => Self::Med
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Speed> for i32 {
|
|
fn from(value: Speed) -> Self {
|
|
match value {
|
|
Speed::Low => 0,
|
|
Speed::Med => 1,
|
|
Speed::High => 2
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Speed> for u8 {
|
|
fn from(s: Speed) -> u8 {
|
|
match s {
|
|
Speed::Low => 0,
|
|
Speed::Med => 1,
|
|
Speed::High => 2
|
|
}
|
|
}
|
|
}
|
|
/// Used for Rainbow mode.
|
|
///
|
|
/// Enum corresponds to the required integer value
|
|
#[cfg_attr(
|
|
feature = "dbus",
|
|
derive(Type, Value, OwnedValue),
|
|
zvariant(signature = "s")
|
|
)]
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub enum Direction {
|
|
#[default]
|
|
Right = 0,
|
|
Left = 1,
|
|
Up = 2,
|
|
Down = 3
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for Direction {
|
|
fn from(value: i32) -> Self {
|
|
match value {
|
|
1 => Self::Left,
|
|
2 => Self::Up,
|
|
3 => Self::Down,
|
|
_ => Self::Right
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Direction> for i32 {
|
|
fn from(value: Direction) -> Self {
|
|
value as i32
|
|
}
|
|
}
|
|
|
|
/// Enum of modes that convert to the actual number required by a USB HID packet
|
|
#[cfg_attr(
|
|
feature = "dbus",
|
|
derive(Type, Value, OwnedValue),
|
|
zvariant(signature = "u")
|
|
)]
|
|
#[derive(
|
|
Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Deserialize, Serialize,
|
|
)]
|
|
pub enum AuraModeNum {
|
|
#[default]
|
|
Static = 0,
|
|
Breathe = 1,
|
|
RainbowCycle = 2,
|
|
RainbowWave = 3,
|
|
Star = 4,
|
|
Rain = 5,
|
|
Highlight = 6,
|
|
Laser = 7,
|
|
Ripple = 8,
|
|
Pulse = 10,
|
|
Comet = 11,
|
|
Flash = 12
|
|
}
|
|
|
|
impl Display for AuraModeNum {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", <&str>::from(self))
|
|
}
|
|
}
|
|
|
|
impl From<AuraModeNum> for String {
|
|
fn from(mode: AuraModeNum) -> Self {
|
|
<&str>::from(&mode).to_owned()
|
|
}
|
|
}
|
|
|
|
impl From<&AuraModeNum> for &str {
|
|
fn from(mode: &AuraModeNum) -> Self {
|
|
match mode {
|
|
AuraModeNum::Static => "Static",
|
|
AuraModeNum::Breathe => "Breathe",
|
|
AuraModeNum::RainbowCycle => "RainbowCycle",
|
|
AuraModeNum::RainbowWave => "RainbowWave",
|
|
AuraModeNum::Star => "Stars",
|
|
AuraModeNum::Rain => "Rain",
|
|
AuraModeNum::Highlight => "Highlight",
|
|
AuraModeNum::Laser => "Laser",
|
|
AuraModeNum::Ripple => "Ripple",
|
|
AuraModeNum::Pulse => "Pulse",
|
|
AuraModeNum::Comet => "Comet",
|
|
AuraModeNum::Flash => "Flash"
|
|
}
|
|
}
|
|
}
|
|
impl From<&str> for AuraModeNum {
|
|
fn from(mode: &str) -> Self {
|
|
match mode {
|
|
"Breathe" => AuraModeNum::Breathe,
|
|
"RainbowCycle" => AuraModeNum::RainbowCycle,
|
|
"RainbowWave" => AuraModeNum::RainbowWave,
|
|
"Stars" => AuraModeNum::Star,
|
|
"Rain" => AuraModeNum::Rain,
|
|
"Highlight" => AuraModeNum::Highlight,
|
|
"Laser" => AuraModeNum::Laser,
|
|
"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 {
|
|
1 => AuraModeNum::Breathe,
|
|
2 => AuraModeNum::RainbowCycle,
|
|
3 => AuraModeNum::RainbowWave,
|
|
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
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for AuraModeNum {
|
|
fn from(mode: i32) -> Self {
|
|
(mode as u8).into()
|
|
}
|
|
}
|
|
|
|
impl From<AuraModeNum> for i32 {
|
|
fn from(value: AuraModeNum) -> Self {
|
|
value as i32
|
|
}
|
|
}
|
|
|
|
impl From<AuraEffect> for AuraModeNum {
|
|
fn from(value: AuraEffect) -> Self {
|
|
value.mode
|
|
}
|
|
}
|
|
|
|
/// Base effects have no zoning, while multizone is 1-4
|
|
#[cfg_attr(
|
|
feature = "dbus",
|
|
derive(Type, Value, OwnedValue),
|
|
zvariant(signature = "u")
|
|
)]
|
|
#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Deserialize, Serialize)]
|
|
pub enum AuraZone {
|
|
/// Used if keyboard has no zones, or if setting all
|
|
#[default]
|
|
None = 0,
|
|
/// Leftmost zone
|
|
Key1 = 1,
|
|
/// Zone after leftmost
|
|
Key2 = 2,
|
|
/// Zone second from right
|
|
Key3 = 3,
|
|
/// Rightmost zone
|
|
Key4 = 4,
|
|
/// Logo on the lid (or elsewhere?)
|
|
Logo = 5,
|
|
/// The left part of a lightbar (typically on the front of laptop)
|
|
BarLeft = 6,
|
|
/// The right part of a lightbar
|
|
BarRight = 7
|
|
}
|
|
|
|
impl FromStr for AuraZone {
|
|
type Err = Error;
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
let s = s.to_lowercase();
|
|
match s.to_ascii_lowercase().as_str() {
|
|
"0" | "none" => Ok(AuraZone::None),
|
|
"1" | "one" => Ok(AuraZone::Key1),
|
|
"2" | "two" => Ok(AuraZone::Key2),
|
|
"3" | "three" => Ok(AuraZone::Key3),
|
|
"4" | "four" => Ok(AuraZone::Key4),
|
|
"5" | "logo" => Ok(AuraZone::Logo),
|
|
"6" | "lightbar-left" => Ok(AuraZone::BarLeft),
|
|
"7" | "lightbar-right" => Ok(AuraZone::BarRight),
|
|
_ => Err(Error::ParseSpeed)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<i32> for AuraZone {
|
|
fn from(value: i32) -> Self {
|
|
match value {
|
|
1 => Self::Key1,
|
|
2 => Self::Key2,
|
|
3 => Self::Key3,
|
|
4 => Self::Key4,
|
|
5 => Self::Logo,
|
|
6 => Self::BarLeft,
|
|
7 => Self::BarRight,
|
|
_ => Self::default()
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<AuraZone> for i32 {
|
|
fn from(value: AuraZone) -> Self {
|
|
value as i32
|
|
}
|
|
}
|
|
|
|
/// Default factory modes structure. This easily converts to an USB HID packet
|
|
/// with:
|
|
/// ```rust
|
|
/// // let bytes: [u8; LED_MSG_LEN] = mode.into();
|
|
/// ```
|
|
#[cfg_attr(feature = "dbus", derive(Type, Value, OwnedValue))]
|
|
#[derive(Debug, Clone, PartialEq, 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) -> &str {
|
|
<&str>::from(&self.mode)
|
|
}
|
|
|
|
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 { r: 166, g: 0, b: 0 },
|
|
colour2: Colour { r: 0, g: 0, b: 0 },
|
|
speed: Speed::Med,
|
|
direction: Direction::Right
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for AuraEffect {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{:?}", self)
|
|
}
|
|
}
|
|
|
|
/// Parses `AuraEffect` in to packet data for writing to the USB interface
|
|
///
|
|
/// Byte structure where colour is RGB, one byte per R, G, B:
|
|
/// ```ignore
|
|
/// | 0 | 1 | 2 | 3 | 4, 5, 6 | 7 | 8 | 9 | 10, 11, 12|
|
|
/// |---|---|-----|-----|---------|------|----------|---|-----------|
|
|
/// |5d |b3 |Zone |Mode |Colour 1 |Speed |Direction |00 |Colour 2 |
|
|
/// ```
|
|
impl From<&AuraEffect> for [u8; AURA_LAPTOP_LED_MSG_LEN] {
|
|
fn from(aura: &AuraEffect) -> Self {
|
|
let mut msg = [0u8; AURA_LAPTOP_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.r;
|
|
msg[5] = aura.colour1.g;
|
|
msg[6] = aura.colour1.b;
|
|
msg[7] = aura.speed as u8;
|
|
msg[8] = aura.direction as u8;
|
|
msg[10] = aura.colour2.r;
|
|
msg[11] = aura.colour2.g;
|
|
msg[12] = aura.colour2.b;
|
|
msg
|
|
}
|
|
}
|
|
|
|
impl From<&AuraEffect> for Vec<u8> {
|
|
fn from(aura: &AuraEffect) -> Self {
|
|
let mut msg = vec![0u8; AURA_LAPTOP_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.r;
|
|
msg[5] = aura.colour1.g;
|
|
msg[6] = aura.colour1.b;
|
|
msg[7] = aura.speed as u8;
|
|
msg[8] = aura.direction as u8;
|
|
msg[10] = aura.colour2.r;
|
|
msg[11] = aura.colour2.g;
|
|
msg[12] = aura.colour2.b;
|
|
msg
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::{
|
|
AuraEffect, AuraModeNum, AuraZone, Colour, Direction, Speed, AURA_LAPTOP_LED_MSG_LEN
|
|
};
|
|
|
|
#[test]
|
|
fn check_led_static_packet() {
|
|
let st = AuraEffect {
|
|
mode: AuraModeNum::Static,
|
|
zone: AuraZone::None,
|
|
colour1: Colour {
|
|
r: 0xff,
|
|
g: 0x11,
|
|
b: 0xdd
|
|
},
|
|
colour2: Colour::default(),
|
|
speed: Speed::Med,
|
|
direction: Direction::Right
|
|
};
|
|
let ar = <[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st);
|
|
|
|
println!("{:02x?}", ar);
|
|
let check = [
|
|
0x5d, 0xb3, 0x0, 0x0, 0xff, 0x11, 0xdd, 0xeb, 0x0, 0x0, 0xa6, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0
|
|
];
|
|
assert_eq!(ar, check);
|
|
}
|
|
|
|
#[test]
|
|
fn check_led_static_zone_packet() {
|
|
let mut st = AuraEffect {
|
|
mode: AuraModeNum::Static,
|
|
zone: AuraZone::Key1,
|
|
colour1: Colour {
|
|
r: 0xff,
|
|
g: 0,
|
|
b: 0
|
|
},
|
|
colour2: Colour { r: 0, g: 0, b: 0 },
|
|
speed: Speed::Low,
|
|
direction: Direction::Left
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x01, 0x00, 0xff, 0x00, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::Key2;
|
|
st.colour1 = Colour {
|
|
r: 0xff,
|
|
g: 0xff,
|
|
b: 0
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x02, 0x00, 0xff, 0xff, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::Key3;
|
|
st.colour1 = Colour {
|
|
r: 0,
|
|
g: 0xff,
|
|
b: 0xff
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x03, 0x00, 0x00, 0xff, 0xff, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::Key4;
|
|
st.colour1 = Colour {
|
|
r: 0xff,
|
|
g: 0x00,
|
|
b: 0xff
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x04, 0x00, 0xff, 0x00, 0xff, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::Logo;
|
|
st.colour1 = Colour {
|
|
r: 0x2c,
|
|
g: 0xff,
|
|
b: 0x00
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x05, 0x00, 0x2c, 0xff, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::BarLeft;
|
|
st.colour1 = Colour {
|
|
r: 0xff,
|
|
g: 0x00,
|
|
b: 0x00
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x06, 0x00, 0xff, 0x00, 0x00, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.zone = AuraZone::BarRight;
|
|
st.colour1 = Colour {
|
|
r: 0xff,
|
|
g: 0x00,
|
|
b: 0xcd
|
|
};
|
|
let capture = [
|
|
0x5d, 0xb3, 0x07, 0x00, 0xff, 0x00, 0xcd, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
|
|
st.mode = AuraModeNum::RainbowWave;
|
|
let capture = [
|
|
0x5d, 0xb3, 0x07, 0x03, 0xff, 0x00, 0xcd, 0xe1, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
|
|
0x0, 0x0
|
|
];
|
|
assert_eq!(
|
|
<[u8; AURA_LAPTOP_LED_MSG_LEN]>::from(&st)[..9],
|
|
capture[..9]
|
|
);
|
|
}
|
|
}
|