First pass of Anime update for new matrix display

Co-authored with @I-Al-Istannen

Part of #189
This commit is contained in:
Luke D. Jones
2022-07-09 15:01:07 +12:00
parent a22808aff3
commit ff76c356c5
21 changed files with 734 additions and 1627 deletions

View File

@@ -13,8 +13,9 @@ edition = "2018"
exclude = ["data"]
[features]
default = ["dbus"]
default = ["dbus", "detect"]
dbus = ["zvariant"]
detect = ["udev", "sysfs-class"]
[dependencies]
png_pong = "^0.8.0"
@@ -28,3 +29,6 @@ serde_derive = "^1.0"
glam = { version = "0.20.5", features = ["serde"] }
zvariant = { version = "^3.0", optional = true }
udev = { version = "^0.6", optional = true }
sysfs-class = { version = "^0.1", optional = true }

View File

@@ -17,10 +17,15 @@ 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;
pub const ANIME_GA401_DATA_LEN: usize = PANE_LEN * 2;
pub const ANIME_GA402_DATA_LEN: usize = PANE_LEN * 3;
/// First packet is for GA401 + GA402
const USB_PREFIX1: [u8; 7] = [0x5e, 0xc0, 0x02, 0x01, 0x00, 0x73, 0x02];
/// Second packet is for GA401 + GA402
const USB_PREFIX2: [u8; 7] = [0x5e, 0xc0, 0x02, 0x74, 0x02, 0x73, 0x02];
/// Third packet is for GA402 matrix
const USB_PREFIX3: [u8; 7] = [0x5e, 0xc0, 0x02, 0xe7, 0x04, 0x73, 0x02];
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, PartialEq, Copy, Clone, Deserialize, Serialize)]
@@ -30,34 +35,46 @@ pub struct AnimePowerStates {
pub boot_anim_enabled: bool,
}
#[cfg_attr(feature = "dbus", derive(Type))]
#[derive(Debug, Copy, Clone, Deserialize, Serialize)]
pub enum AnimeType {
GA401,
GA402,
}
/// 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()
}
pub struct AnimeDataBuffer {
data: Vec<u8>,
anime: AnimeType,
}
impl AnimeDataBuffer {
#[inline]
pub fn new() -> Self {
AnimeDataBuffer(vec![0u8; ANIME_DATA_LEN])
pub fn new(anime: AnimeType) -> Self {
let len = match anime {
AnimeType::GA401 => ANIME_GA401_DATA_LEN,
AnimeType::GA402 => ANIME_GA402_DATA_LEN,
};
AnimeDataBuffer {
data: vec![0u8; len],
anime,
}
}
/// Get the inner data buffer
#[inline]
pub fn get(&self) -> &[u8] {
&self.0
pub fn data(&self) -> &[u8] {
&self.data
}
/// Get a mutable slice of the inner buffer
#[inline]
pub fn get_mut(&mut self) -> &mut [u8] {
&mut self.0
pub fn data_mut(&mut self) -> &mut [u8] {
&mut self.data
}
/// Create from a vector of bytes
@@ -65,25 +82,41 @@ impl AnimeDataBuffer {
/// # 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)
pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Self {
match anime {
AnimeType::GA401 => assert_eq!(data.len(), ANIME_GA401_DATA_LEN),
AnimeType::GA402 => assert_eq!(data.len(), ANIME_GA402_DATA_LEN),
}
Self { data, anime }
}
}
/// The two packets to be written to USB
pub type AnimePacketType = [[u8; 640]; 2];
pub type AnimePacketType = Vec<[u8; 640]>;
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() {
let mut buffers = match anime.anime {
AnimeType::GA401 => {
assert!(anime.data.len() == ANIME_GA401_DATA_LEN);
vec![[0; 640]; 2]
}
AnimeType::GA402 => {
assert!(anime.data.len() == ANIME_GA402_DATA_LEN);
vec![[0; 640]; 3]
}
};
for (idx, chunk) in anime.data.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);
if matches!(anime.anime, AnimeType::GA402) {
buffers[2][..7].copy_from_slice(&USB_PREFIX3);
}
buffers
}
}
@@ -142,7 +175,7 @@ pub fn run_animation(
if let AnimTime::Fade(_) = frames.duration() {
if frame_start <= start + fade_in {
for pixel in output.get_mut() {
for pixel in output.data_mut() {
*pixel = (*pixel as f32 * fade_in_accum) as u8;
}
fade_in_accum = fade_in_step * (frame_start - start).as_secs_f32();
@@ -153,7 +186,7 @@ pub fn run_animation(
} else {
fade_out_accum = 0.0;
}
for pixel in output.get_mut() {
for pixel in output.data_mut() {
*pixel = (*pixel as f32 * fade_out_accum) as u8;
}
}

View File

@@ -1,11 +1,13 @@
use std::{path::Path, time::Duration};
use crate::{
data::{AnimeDataBuffer, ANIME_DATA_LEN},
data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN},
error::AnimeError,
AnimeType, ANIME_GA402_DATA_LEN,
};
const WIDTH: usize = 74;
// TODO: Change for GA402
const HEIGHT: usize = 36;
/// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images)
@@ -127,71 +129,262 @@ impl AnimeDiagonal {
}
}
}
}
impl From<&AnimeDiagonal> for AnimeDataBuffer {
/// Convert to a data buffer that can be sent over dbus
#[inline]
pub fn into_data_buffer(&self, anime_type: AnimeType) -> AnimeDataBuffer {
match anime_type {
AnimeType::GA401 => self.into_ga401_packets(),
AnimeType::GA402 => self.into_ga402_packets(),
}
}
/// Do conversion from the nested Vec in AnimeMatrix to the two required
/// packets suitable for sending over USB
#[inline]
fn from(anime: &AnimeDiagonal) -> Self {
let mut buf = vec![0u8; ANIME_DATA_LEN];
fn into_ga401_packets(&self) -> AnimeDataBuffer {
let mut buf = vec![0u8; ANIME_GA401_DATA_LEN];
buf[1..=32].copy_from_slice(&anime.get_row(0, 3, 32));
buf[34..=66].copy_from_slice(&anime.get_row(0, 2, 33));
buf[69..=101].copy_from_slice(&anime.get_row(1, 2, 33)); // ?!
buf[102..=134].copy_from_slice(&anime.get_row(1, 1, 33));
buf[137..=169].copy_from_slice(&anime.get_row(2, 1, 33));
buf[170..=202].copy_from_slice(&anime.get_row(2, 0, 33));
buf[204..=236].copy_from_slice(&anime.get_row(3, 0, 33));
buf[237..=268].copy_from_slice(&anime.get_row(4, 0, 32));
buf[270..=301].copy_from_slice(&anime.get_row(5, 0, 32));
buf[302..=332].copy_from_slice(&anime.get_row(6, 0, 31));
buf[334..=364].copy_from_slice(&anime.get_row(7, 0, 31));
buf[365..=394].copy_from_slice(&anime.get_row(8, 0, 30));
buf[396..=425].copy_from_slice(&anime.get_row(9, 0, 30));
buf[426..=454].copy_from_slice(&anime.get_row(10, 0, 29));
buf[456..=484].copy_from_slice(&anime.get_row(11, 0, 29));
buf[485..=512].copy_from_slice(&anime.get_row(12, 0, 28));
buf[514..=541].copy_from_slice(&anime.get_row(13, 0, 28));
buf[542..=568].copy_from_slice(&anime.get_row(14, 0, 27));
buf[570..=596].copy_from_slice(&anime.get_row(15, 0, 27));
buf[597..=622].copy_from_slice(&anime.get_row(16, 0, 26));
buf[624..=649].copy_from_slice(&anime.get_row(17, 0, 26));
buf[650..=674].copy_from_slice(&anime.get_row(18, 0, 25));
buf[676..=700].copy_from_slice(&anime.get_row(19, 0, 25));
buf[701..=724].copy_from_slice(&anime.get_row(20, 0, 24));
buf[726..=749].copy_from_slice(&anime.get_row(21, 0, 24));
buf[750..=772].copy_from_slice(&anime.get_row(22, 0, 23));
buf[774..=796].copy_from_slice(&anime.get_row(23, 0, 23));
buf[797..=818].copy_from_slice(&anime.get_row(24, 0, 22));
buf[820..=841].copy_from_slice(&anime.get_row(25, 0, 22));
buf[842..=862].copy_from_slice(&anime.get_row(26, 0, 21));
buf[864..=884].copy_from_slice(&anime.get_row(27, 0, 21));
buf[885..=904].copy_from_slice(&anime.get_row(28, 0, 20));
buf[906..=925].copy_from_slice(&anime.get_row(29, 0, 20));
buf[926..=944].copy_from_slice(&anime.get_row(30, 0, 19));
buf[946..=964].copy_from_slice(&anime.get_row(31, 0, 19));
buf[965..=982].copy_from_slice(&anime.get_row(32, 0, 18));
buf[984..=1001].copy_from_slice(&anime.get_row(33, 0, 18));
buf[1002..=1018].copy_from_slice(&anime.get_row(34, 0, 17));
buf[1020..=1036].copy_from_slice(&anime.get_row(35, 0, 17));
buf[1037..=1052].copy_from_slice(&anime.get_row(36, 0, 16));
buf[1054..=1069].copy_from_slice(&anime.get_row(37, 0, 16));
buf[1070..=1084].copy_from_slice(&anime.get_row(38, 0, 15));
buf[1086..=1100].copy_from_slice(&anime.get_row(39, 0, 15));
buf[1101..=1114].copy_from_slice(&anime.get_row(40, 0, 14));
buf[1116..=1129].copy_from_slice(&anime.get_row(41, 0, 14));
buf[1130..=1142].copy_from_slice(&anime.get_row(42, 0, 13));
buf[1144..=1156].copy_from_slice(&anime.get_row(43, 0, 13));
buf[1157..=1168].copy_from_slice(&anime.get_row(44, 0, 12));
buf[1170..=1181].copy_from_slice(&anime.get_row(45, 0, 12));
buf[1182..=1192].copy_from_slice(&anime.get_row(46, 0, 11));
buf[1194..=1204].copy_from_slice(&anime.get_row(47, 0, 11));
buf[1205..=1214].copy_from_slice(&anime.get_row(48, 0, 10));
buf[1216..=1225].copy_from_slice(&anime.get_row(49, 0, 10));
buf[1226..=1234].copy_from_slice(&anime.get_row(50, 0, 9));
buf[1236..=1244].copy_from_slice(&anime.get_row(51, 0, 9));
buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32));
buf[34..=66].copy_from_slice(&self.get_row(0, 2, 33));
buf[69..=101].copy_from_slice(&self.get_row(1, 2, 33)); // ?!
buf[102..=134].copy_from_slice(&self.get_row(1, 1, 33));
buf[137..=169].copy_from_slice(&self.get_row(2, 1, 33));
buf[170..=202].copy_from_slice(&self.get_row(2, 0, 33));
buf[204..=236].copy_from_slice(&self.get_row(3, 0, 33));
buf[237..=268].copy_from_slice(&self.get_row(4, 0, 32));
buf[270..=301].copy_from_slice(&self.get_row(5, 0, 32));
buf[302..=332].copy_from_slice(&self.get_row(6, 0, 31));
buf[334..=364].copy_from_slice(&self.get_row(7, 0, 31));
buf[365..=394].copy_from_slice(&self.get_row(8, 0, 30));
buf[396..=425].copy_from_slice(&self.get_row(9, 0, 30));
buf[426..=454].copy_from_slice(&self.get_row(10, 0, 29));
buf[456..=484].copy_from_slice(&self.get_row(11, 0, 29));
buf[485..=512].copy_from_slice(&self.get_row(12, 0, 28));
buf[514..=541].copy_from_slice(&self.get_row(13, 0, 28));
buf[542..=568].copy_from_slice(&self.get_row(14, 0, 27));
buf[570..=596].copy_from_slice(&self.get_row(15, 0, 27));
buf[597..=622].copy_from_slice(&self.get_row(16, 0, 26));
buf[624..=649].copy_from_slice(&self.get_row(17, 0, 26));
buf[650..=674].copy_from_slice(&self.get_row(18, 0, 25));
buf[676..=700].copy_from_slice(&self.get_row(19, 0, 25));
buf[701..=724].copy_from_slice(&self.get_row(20, 0, 24));
buf[726..=749].copy_from_slice(&self.get_row(21, 0, 24));
buf[750..=772].copy_from_slice(&self.get_row(22, 0, 23));
buf[774..=796].copy_from_slice(&self.get_row(23, 0, 23));
buf[797..=818].copy_from_slice(&self.get_row(24, 0, 22));
buf[820..=841].copy_from_slice(&self.get_row(25, 0, 22));
buf[842..=862].copy_from_slice(&self.get_row(26, 0, 21));
buf[864..=884].copy_from_slice(&self.get_row(27, 0, 21));
buf[885..=904].copy_from_slice(&self.get_row(28, 0, 20));
buf[906..=925].copy_from_slice(&self.get_row(29, 0, 20));
buf[926..=944].copy_from_slice(&self.get_row(30, 0, 19));
buf[946..=964].copy_from_slice(&self.get_row(31, 0, 19));
buf[965..=982].copy_from_slice(&self.get_row(32, 0, 18));
buf[984..=1001].copy_from_slice(&self.get_row(33, 0, 18));
buf[1002..=1018].copy_from_slice(&self.get_row(34, 0, 17));
buf[1020..=1036].copy_from_slice(&self.get_row(35, 0, 17));
buf[1037..=1052].copy_from_slice(&self.get_row(36, 0, 16));
buf[1054..=1069].copy_from_slice(&self.get_row(37, 0, 16));
buf[1070..=1084].copy_from_slice(&self.get_row(38, 0, 15));
buf[1086..=1100].copy_from_slice(&self.get_row(39, 0, 15));
buf[1101..=1114].copy_from_slice(&self.get_row(40, 0, 14));
buf[1116..=1129].copy_from_slice(&self.get_row(41, 0, 14));
buf[1130..=1142].copy_from_slice(&self.get_row(42, 0, 13));
buf[1144..=1156].copy_from_slice(&self.get_row(43, 0, 13));
buf[1157..=1168].copy_from_slice(&self.get_row(44, 0, 12));
buf[1170..=1181].copy_from_slice(&self.get_row(45, 0, 12));
buf[1182..=1192].copy_from_slice(&self.get_row(46, 0, 11));
buf[1194..=1204].copy_from_slice(&self.get_row(47, 0, 11));
buf[1205..=1214].copy_from_slice(&self.get_row(48, 0, 10));
buf[1216..=1225].copy_from_slice(&self.get_row(49, 0, 10));
buf[1226..=1234].copy_from_slice(&self.get_row(50, 0, 9));
buf[1236..=1244].copy_from_slice(&self.get_row(51, 0, 9));
AnimeDataBuffer::from_vec(buf)
AnimeDataBuffer::from_vec(crate::AnimeType::GA401, buf)
}
fn into_ga402_packets(&self) -> AnimeDataBuffer {
let mut buf = vec![0u8; ANIME_GA402_DATA_LEN];
let mut start_index: usize = 0;
fn copy_slice(
buf: &mut Vec<u8>,
anime: &AnimeDiagonal,
x: usize,
y: usize,
start_index: &mut usize,
len: usize,
) {
buf[*start_index..*start_index + len].copy_from_slice(&anime.get_row(x, y, len));
*start_index += len;
}
let b = &mut buf;
let a = &self;
copy_slice(b, a, 0, 5, &mut start_index, 34);
copy_slice(b, a, 1, 5, &mut start_index, 34);
copy_slice(b, a, 1, 4, &mut start_index, 34);
copy_slice(b, a, 2, 4, &mut start_index, 34);
copy_slice(b, a, 2, 3, &mut start_index, 34);
copy_slice(b, a, 3, 3, &mut start_index, 34);
copy_slice(b, a, 3, 2, &mut start_index, 34);
copy_slice(b, a, 4, 2, &mut start_index, 34);
copy_slice(b, a, 4, 1, &mut start_index, 34);
copy_slice(b, a, 5, 1, &mut start_index, 34);
copy_slice(b, a, 5, 0, &mut start_index, 34);
copy_slice(b, a, 6, 0, &mut start_index, 34);
copy_slice(b, a, 7, 0, &mut start_index, 33);
copy_slice(b, a, 8, 0, &mut start_index, 33);
copy_slice(b, a, 9, 0, &mut start_index, 32);
copy_slice(b, a, 10, 0, &mut start_index, 32);
copy_slice(b, a, 11, 0, &mut start_index, 31);
copy_slice(b, a, 12, 0, &mut start_index, 31);
copy_slice(b, a, 13, 0, &mut start_index, 30);
copy_slice(b, a, 14, 0, &mut start_index, 30);
copy_slice(b, a, 15, 0, &mut start_index, 29);
copy_slice(b, a, 16, 0, &mut start_index, 29);
copy_slice(b, a, 17, 0, &mut start_index, 28);
copy_slice(b, a, 18, 0, &mut start_index, 28);
copy_slice(b, a, 19, 0, &mut start_index, 27);
copy_slice(b, a, 20, 0, &mut start_index, 27);
copy_slice(b, a, 21, 0, &mut start_index, 26);
copy_slice(b, a, 22, 0, &mut start_index, 26);
copy_slice(b, a, 23, 0, &mut start_index, 25);
copy_slice(b, a, 24, 0, &mut start_index, 25);
copy_slice(b, a, 25, 0, &mut start_index, 24);
copy_slice(b, a, 26, 0, &mut start_index, 24);
copy_slice(b, a, 27, 0, &mut start_index, 23);
copy_slice(b, a, 28, 0, &mut start_index, 23);
copy_slice(b, a, 29, 0, &mut start_index, 22);
copy_slice(b, a, 30, 0, &mut start_index, 22);
copy_slice(b, a, 31, 0, &mut start_index, 21);
copy_slice(b, a, 32, 0, &mut start_index, 21);
copy_slice(b, a, 33, 0, &mut start_index, 20);
copy_slice(b, a, 34, 0, &mut start_index, 20);
copy_slice(b, a, 35, 0, &mut start_index, 19);
copy_slice(b, a, 36, 0, &mut start_index, 19);
copy_slice(b, a, 37, 0, &mut start_index, 18);
copy_slice(b, a, 38, 0, &mut start_index, 18);
copy_slice(b, a, 39, 0, &mut start_index, 17);
copy_slice(b, a, 40, 0, &mut start_index, 17);
copy_slice(b, a, 41, 0, &mut start_index, 16);
copy_slice(b, a, 42, 0, &mut start_index, 16);
copy_slice(b, a, 43, 0, &mut start_index, 15);
copy_slice(b, a, 44, 0, &mut start_index, 15);
copy_slice(b, a, 45, 0, &mut start_index, 14);
copy_slice(b, a, 46, 0, &mut start_index, 14);
copy_slice(b, a, 47, 0, &mut start_index, 13);
copy_slice(b, a, 48, 0, &mut start_index, 13);
copy_slice(b, a, 49, 0, &mut start_index, 12);
copy_slice(b, a, 50, 0, &mut start_index, 12);
copy_slice(b, a, 51, 0, &mut start_index, 11);
copy_slice(b, a, 52, 0, &mut start_index, 11);
copy_slice(b, a, 53, 0, &mut start_index, 10);
copy_slice(b, a, 54, 0, &mut start_index, 10);
copy_slice(b, a, 55, 0, &mut start_index, 9);
AnimeDataBuffer::from_vec(crate::AnimeType::GA402, buf)
}
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::{AnimeDiagonal, AnimePacketType};
#[test]
fn ga401_diagonal_packet_check() {
let pkt0_check = [
0x5e, 0xc0, 0x2, 0x1, 0x0, 0x73, 0x2, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0xff, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff,
0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0,
];
let pkt1_check = [
0x5e, 0xc0, 0x2, 0x74, 0x2, 0x73, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0xff, 0x0, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
];
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("test/ga401-diagonal.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0).unwrap();
let data = matrix.into_data_buffer(crate::AnimeType::GA401);
let pkt = AnimePacketType::from(data);
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
}
}

View File

@@ -13,6 +13,9 @@ pub enum AnimeError {
/// The input was incorrect size, expected size is `IncorrectSize(width, height)`
IncorrectSize(u32, u32),
Dbus(String),
Udev(String, std::io::Error),
NoDevice,
UnsupportedDevice,
}
impl fmt::Display for AnimeError {
@@ -30,6 +33,9 @@ impl fmt::Display for AnimeError {
width, height
),
AnimeError::Dbus(detail) => write!(f, "{}", detail),
AnimeError::Udev(deets, error) => write!(f, "udev {}: {}", deets, error),
AnimeError::NoDevice => write!(f, "No AniMe Matrix device found"),
AnimeError::UnsupportedDevice => write!(f, "Unsupported AniMe Matrix device found"),
}
}
}

View File

@@ -2,7 +2,7 @@ use glam::Vec2;
use serde_derive::{Deserialize, Serialize};
use std::{fs::File, path::Path, time::Duration};
use crate::{error::AnimeError, AnimeDataBuffer, AnimeDiagonal, AnimeImage, Pixel};
use crate::{error::AnimeError, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AnimeFrame {
@@ -90,8 +90,10 @@ impl AnimeGif {
#[inline]
pub fn from_diagonal_gif(
file_name: &Path,
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
let mut matrix = AnimeDiagonal::new(None);
@@ -121,7 +123,7 @@ impl AnimeGif {
}
frames.push(AnimeFrame {
data: <AnimeDataBuffer>::from(&matrix),
data: matrix.into_data_buffer(anime_type),
delay: Duration::from_millis(wait as u64),
});
}
@@ -132,6 +134,7 @@ impl AnimeGif {
#[inline]
pub fn from_diagonal_png(
file_name: &Path,
anime_type: AnimeType,
duration: AnimTime,
brightness: f32,
) -> Result<Self, AnimeError> {
@@ -148,7 +151,7 @@ impl AnimeGif {
let frame_count = total.as_millis() / 30;
let single = AnimeFrame {
data: <AnimeDataBuffer>::from(&image),
data: image.into_data_buffer(anime_type),
delay: Duration::from_millis(30),
};
let frames = vec![single; frame_count as usize];
@@ -166,6 +169,7 @@ impl AnimeGif {
translation: Vec2,
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
let mut frames = Vec::new();
@@ -187,6 +191,7 @@ impl AnimeGif {
brightness,
pixels,
decoder.width() as u32,
anime_type,
);
while let Some(frame) = decoder.read_next_frame()? {
@@ -201,6 +206,7 @@ impl AnimeGif {
brightness,
pixels,
width as u32,
anime_type,
);
}
for (y, row) in frame.buffer.chunks(frame.width as usize * 4).enumerate() {
@@ -238,8 +244,10 @@ impl AnimeGif {
translation: Vec2,
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
let image = AnimeImage::from_png(file_name, scale, angle, translation, brightness)?;
let image =
AnimeImage::from_png(file_name, scale, angle, translation, brightness, anime_type)?;
let mut total = Duration::from_millis(1000);
if let AnimTime::Fade(fade) = duration {

View File

@@ -1,8 +1,7 @@
use std::time::Duration;
use crate::data::{AnimeDataBuffer, ANIME_DATA_LEN};
use crate::image::LED_IMAGE_POSITIONS;
use crate::data::{AnimeDataBuffer, ANIME_GA401_DATA_LEN};
use crate::{AnimeImage, AnimeType, ANIME_GA402_DATA_LEN};
// TODO: Adjust these sizes as WIDTH_GA401 WIDTH_GA402
const WIDTH: usize = 33;
const HEIGHT: usize = 55;
@@ -14,41 +13,40 @@ const HEIGHT: usize = 55;
///
/// **Note:** the columns in each odd row are offset by half a pixel left
#[derive(Debug, Clone)]
pub struct AnimeGrid([[u8; WIDTH]; HEIGHT], Option<Duration>);
impl Default for AnimeGrid {
#[inline]
fn default() -> Self {
Self::new(None)
}
pub struct AnimeGrid {
anime_type: AnimeType,
data: [[u8; WIDTH]; HEIGHT],
}
impl AnimeGrid {
#[inline]
pub fn new(duration: Option<Duration>) -> Self {
AnimeGrid([[0u8; WIDTH]; HEIGHT], duration)
pub fn new(anime_type: AnimeType) -> Self {
Self {
anime_type,
data: [[0u8; WIDTH]; HEIGHT],
}
}
/// Set a position in the grid with a brightness value
#[inline]
pub fn set(&mut self, x: usize, y: usize, b: u8) {
self.0[y][x] = b;
self.data[y][x] = b;
}
#[inline]
pub fn get(&self) -> &[[u8; WIDTH]; HEIGHT] {
&self.0
&self.data
}
#[inline]
pub fn get_mut(&mut self) -> &mut [[u8; WIDTH]; HEIGHT] {
&mut self.0
&mut self.data
}
/// Fill the grid with a value
#[inline]
pub fn fill_with(&mut self, fill: u8) {
for row in self.0.iter_mut() {
for row in self.data.iter_mut() {
for x in row.iter_mut() {
*x = fill;
}
@@ -94,16 +92,22 @@ impl From<AnimeGrid> for AnimeDataBuffer {
/// packets suitable for sending over USB
#[inline]
fn from(anime: AnimeGrid) -> Self {
let mut buf = vec![0u8; ANIME_DATA_LEN];
let mut buf = match anime.anime_type {
AnimeType::GA401 => vec![0u8; ANIME_GA401_DATA_LEN],
AnimeType::GA402 => vec![0u8; ANIME_GA402_DATA_LEN],
};
for (idx, pos) in LED_IMAGE_POSITIONS.iter().enumerate() {
for (idx, pos) in AnimeImage::generate_image_positioning(anime.anime_type)
.iter()
.enumerate()
{
if let Some(pos) = pos {
let x = pos.x().ceil() as usize;
let y = pos.y().ceil() as usize;
buf[idx + 1] = anime.0[y][x];
buf[idx + 1] = anime.data[y][x];
}
}
AnimeDataBuffer::from_vec(buf)
AnimeDataBuffer::from_vec(anime.anime_type, buf)
}
}
@@ -113,7 +117,7 @@ mod tests {
#[test]
fn check_data_alignment() {
let mut matrix = AnimeGrid::new(None);
let mut matrix = AnimeGrid::new(AnimeType::GA401);
{
let tmp = matrix.get_mut();
for row in tmp.iter_mut() {
@@ -171,6 +175,6 @@ mod tests {
0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0,
0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
assert_eq!(matrix.get(), &data_cmp);
assert_eq!(matrix.data(), &data_cmp);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,9 @@ use std::{path::PathBuf, time::Duration};
use glam::Vec2;
use serde_derive::{Deserialize, Serialize};
use crate::{error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage};
use crate::{
error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType,
};
/// All the possible AniMe actions that can be used. This enum is intended to be
/// a helper for loading up `ActionData`.
@@ -63,13 +65,21 @@ pub enum ActionData {
}
impl ActionData {
pub fn from_anime_action(action: &ActionLoader) -> Result<ActionData, AnimeError> {
pub fn from_anime_action(
anime_type: AnimeType,
action: &ActionLoader,
) -> Result<ActionData, AnimeError> {
let a = match action {
ActionLoader::AsusAnimation {
file,
time,
brightness,
} => ActionData::Animation(AnimeGif::from_diagonal_gif(file, *time, *brightness)?),
} => ActionData::Animation(AnimeGif::from_diagonal_gif(
file,
*time,
*brightness,
anime_type,
)?),
ActionLoader::AsusImage {
file,
time,
@@ -77,10 +87,15 @@ impl ActionData {
} => match time {
AnimTime::Infinite => {
let image = AnimeDiagonal::from_png(file, None, *brightness)?;
let data = <AnimeDataBuffer>::from(&image);
let data = image.into_data_buffer(anime_type);
ActionData::Image(Box::new(data))
}
_ => ActionData::Animation(AnimeGif::from_diagonal_png(file, *time, *brightness)?),
_ => ActionData::Animation(AnimeGif::from_diagonal_png(
file,
anime_type,
*time,
*brightness,
)?),
},
ActionLoader::ImageAnimation {
file,
@@ -99,6 +114,7 @@ impl ActionData {
*translation,
*time,
*brightness,
anime_type,
)?));
}
}
@@ -109,6 +125,7 @@ impl ActionData {
*translation,
*time,
*brightness,
anime_type,
)?)
}
ActionLoader::Image {
@@ -122,8 +139,14 @@ impl ActionData {
match time {
AnimTime::Infinite => {
// If no time then create a plain static image
let image =
AnimeImage::from_png(file, *scale, *angle, *translation, *brightness)?;
let image = AnimeImage::from_png(
file,
*scale,
*angle,
*translation,
*brightness,
anime_type,
)?;
let data = <AnimeDataBuffer>::from(&image);
ActionData::Image(Box::new(data))
}
@@ -134,6 +157,7 @@ impl ActionData {
*translation,
*time,
*brightness,
anime_type,
)?),
}
}
@@ -144,20 +168,21 @@ impl ActionData {
}
/// An optimised precomputed set of actions that the user can cycle through
#[derive(Debug, Deserialize, Serialize, Default)]
pub struct Sequences(Vec<ActionData>);
#[derive(Debug, Deserialize, Serialize)]
pub struct Sequences(Vec<ActionData>, AnimeType);
impl Sequences {
#[inline]
pub fn new() -> Self {
Self(Vec::new())
pub fn new(anime_type: AnimeType) -> Self {
Self(Vec::new(), anime_type)
}
/// Use a base `AnimeAction` to generate the precomputed data and insert in to
/// the run buffer
#[inline]
pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<(), AnimeError> {
self.0.insert(index, ActionData::from_anime_action(action)?);
self.0
.insert(index, ActionData::from_anime_action(self.1, action)?);
Ok(())
}

View File

@@ -7,6 +7,8 @@
//!
//! Step 1 need to applied only on fresh system boot.
use crate::{error::AnimeError, AnimeType};
const INIT_STR: [u8; 15] = [
0x5e, b'A', b'S', b'U', b'S', b' ', b'T', b'e', b'c', b'h', b'.', b'I', b'n', b'c', b'.',
];
@@ -15,6 +17,47 @@ const DEV_PAGE: u8 = 0x5e;
pub const VENDOR_ID: u16 = 0x0b05;
pub const PROD_ID: u16 = 0x193b;
/// `get_anime_type` is very broad, matching on part of the laptop board name only. For this
/// reason `find_node()` must be used also to verify if the USB device is available.
///
/// The currently known USB device is `19b6`.
#[inline]
pub fn get_anime_type() -> Result<AnimeType, AnimeError> {
let dmi = sysfs_class::DmiId::default();
let board_name = dmi.board_name()?;
if board_name.contains("GA401Q") {
return Ok(AnimeType::GA401);
} else if board_name.contains("GA401R") {
return Ok(AnimeType::GA402);
}
Err(AnimeError::UnsupportedDevice)
}
/// Find the USB device node - known devices so far: `19b6`
#[inline]
pub fn find_node(id_product: &str) -> Result<String, AnimeError> {
let mut enumerator =
udev::Enumerator::new().map_err(|err| AnimeError::Udev("enumerator failed".into(), err))?;
enumerator
.match_subsystem("usb")
.map_err(|err| AnimeError::Udev("match_subsystem failed".into(), err))?;
for device in enumerator
.scan_devices()
.map_err(|err| AnimeError::Udev("scan_devices failed".into(), err))?
{
if let Some(attr) = device.attribute_value("idProduct") {
if attr == id_product {
if let Some(dev_node) = device.devnode() {
return Ok(dev_node.to_string_lossy().to_string());
}
}
}
}
Err(AnimeError::NoDevice)
}
/// Get the two device initialization packets. These are required for device start
/// after the laptop boots.
#[inline]

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B