Make rog-anime more tolerent of faults

This commit is contained in:
Luke D. Jones
2022-07-20 11:10:41 +12:00
parent 42fc5a5392
commit a71a40b509
18 changed files with 153 additions and 91 deletions

View File

@@ -14,7 +14,7 @@ exclude = ["data"]
[features]
default = ["dbus", "detect"]
dbus = ["zvariant"]
dbus = ["zvariant", "zbus"]
detect = ["udev", "sysfs-class"]
[dependencies]
@@ -29,6 +29,7 @@ serde_derive = "^1.0"
glam = { version = "0.20.5", features = ["serde"] }
zvariant = { version = "^3.0", optional = true }
zbus = { version = "^2.2", optional = true }
udev = { version = "^0.6", optional = true }
sysfs-class = { version = "^0.1", optional = true }

View File

@@ -1,4 +1,5 @@
use std::{
convert::TryFrom,
thread::sleep,
time::{Duration, Instant},
};
@@ -8,7 +9,10 @@ use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "dbus")]
use zvariant::Type;
use crate::{error::AnimeError, AnimTime, AnimeGif};
use crate::{
error::{AnimeError, Result},
AnimTime, AnimeGif,
};
/// The first 7 bytes of a USB packet are accounted for by `USB_PREFIX1` and `USB_PREFIX2`
const BLOCK_START: usize = 7;
@@ -102,20 +106,25 @@ impl AnimeDataBuffer {
/// # Panics
/// Will panic if the vector length is not `ANIME_DATA_LEN`
#[inline]
pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Self {
assert_eq!(data.len(), anime.data_length());
pub fn from_vec(anime: AnimeType, data: Vec<u8>) -> Result<Self> {
if data.len() != anime.data_length() {
return Err(AnimeError::DataBufferLength);
}
Self { data, anime }
Ok(Self { data, anime })
}
}
/// The two packets to be written to USB
pub type AnimePacketType = Vec<[u8; 640]>;
impl From<AnimeDataBuffer> for AnimePacketType {
#[inline]
fn from(anime: AnimeDataBuffer) -> Self {
assert_eq!(anime.data.len(), anime.anime.data_length());
impl TryFrom<AnimeDataBuffer> for AnimePacketType {
type Error = AnimeError;
fn try_from(anime: AnimeDataBuffer) -> std::result::Result<Self, Self::Error> {
if anime.data.len() != anime.anime.data_length() {
return Err(AnimeError::DataBufferLength);
}
let mut buffers = match anime.anime {
AnimeType::GA401 => vec![[0; 640]; 2],
@@ -131,7 +140,7 @@ impl From<AnimeDataBuffer> for AnimePacketType {
if matches!(anime.anime, AnimeType::GA402) {
buffers[2][..7].copy_from_slice(&USB_PREFIX3);
}
buffers
Ok(buffers)
}
}
@@ -140,8 +149,8 @@ impl From<AnimeDataBuffer> for AnimePacketType {
/// If `callback` is `Ok(true)` then `run_animation` will exit the animation loop early.
pub fn run_animation(
frames: &AnimeGif,
callback: &dyn Fn(AnimeDataBuffer) -> Result<bool, AnimeError>,
) -> Result<(), AnimeError> {
callback: &dyn Fn(AnimeDataBuffer) -> Result<bool>,
) -> Result<()> {
let mut count = 0;
let start = Instant::now();

View File

@@ -1,6 +1,10 @@
use std::{path::Path, time::Duration};
use crate::{data::AnimeDataBuffer, error::AnimeError, AnimeType};
use crate::{
data::AnimeDataBuffer,
error::{AnimeError, Result},
AnimeType,
};
/// Mostly intended to be used with ASUS gifs, but can be used for other purposes (like images)
#[derive(Debug, Clone)]
@@ -40,7 +44,7 @@ impl AnimeDiagonal {
duration: Option<Duration>,
bright: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let data = std::fs::read(path)?;
let data = std::io::Cursor::new(data);
let decoder = png_pong::Decoder::new(data)?.into_steps();
@@ -125,7 +129,7 @@ impl AnimeDiagonal {
/// Convert to a data buffer that can be sent over dbus
#[inline]
pub fn into_data_buffer(&self, anime_type: AnimeType) -> AnimeDataBuffer {
pub fn into_data_buffer(&self, anime_type: AnimeType) -> Result<AnimeDataBuffer> {
match anime_type {
AnimeType::GA401 => self.into_ga401_packets(),
AnimeType::GA402 => self.into_ga402_packets(),
@@ -134,7 +138,7 @@ impl AnimeDiagonal {
/// Do conversion from the nested Vec in AnimeMatrix to the two required
/// packets suitable for sending over USB
fn into_ga401_packets(&self) -> AnimeDataBuffer {
fn into_ga401_packets(&self) -> Result<AnimeDataBuffer> {
let mut buf = vec![0u8; AnimeType::GA401.data_length()];
buf[1..=32].copy_from_slice(&self.get_row(0, 3, 32));
@@ -196,7 +200,7 @@ impl AnimeDiagonal {
AnimeDataBuffer::from_vec(crate::AnimeType::GA401, buf)
}
fn into_ga402_packets(&self) -> AnimeDataBuffer {
fn into_ga402_packets(&self) -> Result<AnimeDataBuffer> {
let mut buf = vec![0u8; AnimeType::GA402.data_length()];
let mut start_index: usize = 0;
@@ -282,7 +286,7 @@ impl AnimeDiagonal {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use std::{convert::TryFrom, path::PathBuf};
use crate::{AnimeDiagonal, AnimePacketType, AnimeType};
@@ -374,8 +378,8 @@ mod tests {
path.push("test/ga401-diagonal.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA401).unwrap();
let data = matrix.into_data_buffer(crate::AnimeType::GA401);
let pkt = AnimePacketType::from(data);
let data = matrix.into_data_buffer(crate::AnimeType::GA401).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
@@ -509,8 +513,8 @@ mod tests {
path.push("test/ga402-diagonal.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA402).unwrap();
let data = matrix.into_data_buffer(crate::AnimeType::GA402);
let pkt = AnimePacketType::from(data);
let data = matrix.into_data_buffer(crate::AnimeType::GA402).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
@@ -654,8 +658,8 @@ mod tests {
path.push("test/ga402-diagonal-fullbright.png");
let matrix = AnimeDiagonal::from_png(&path, None, 255.0, AnimeType::GA402).unwrap();
let data = matrix.into_data_buffer(crate::AnimeType::GA402);
let pkt = AnimePacketType::from(data);
let data = matrix.into_data_buffer(crate::AnimeType::GA402).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);

View File

@@ -3,6 +3,8 @@ use png_pong::decode::Error as PngError;
use std::error::Error;
use std::fmt;
pub type Result<T> = std::result::Result<T, AnimeError>;
#[derive(Debug)]
pub enum AnimeError {
NoFrames,
@@ -17,6 +19,7 @@ pub enum AnimeError {
NoDevice,
UnsupportedDevice,
InvalidBrightness(f32),
DataBufferLength,
}
impl fmt::Display for AnimeError {
@@ -36,6 +39,10 @@ impl fmt::Display for AnimeError {
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::DataBufferLength => write!(
f,
"The data buffer was incorrect length for generating USB packets"
),
AnimeError::UnsupportedDevice => write!(f, "Unsupported AniMe Matrix device found"),
AnimeError::InvalidBrightness(bright) => write!(
f,
@@ -68,3 +75,10 @@ impl From<DecodingError> for AnimeError {
AnimeError::Gif(err)
}
}
impl From<AnimeError> for zbus::fdo::Error {
#[inline]
fn from(err: AnimeError) -> Self {
zbus::fdo::Error::Failed(format!("{}", err))
}
}

View File

@@ -1,8 +1,9 @@
use glam::Vec2;
use serde_derive::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::{fs::File, path::Path, time::Duration};
use crate::{error::AnimeError, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel};
use crate::{error::Result, AnimeDataBuffer, AnimeDiagonal, AnimeImage, AnimeType, Pixel};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct AnimeFrame {
@@ -93,7 +94,7 @@ impl AnimeGif {
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let mut matrix = AnimeDiagonal::new(anime_type, None);
let mut decoder = gif::DecodeOptions::new();
@@ -122,7 +123,7 @@ impl AnimeGif {
}
frames.push(AnimeFrame {
data: matrix.into_data_buffer(anime_type),
data: matrix.into_data_buffer(anime_type)?,
delay: Duration::from_millis(wait as u64),
});
}
@@ -136,7 +137,7 @@ impl AnimeGif {
anime_type: AnimeType,
duration: AnimTime,
brightness: f32,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let image = AnimeDiagonal::from_png(file_name, None, brightness, anime_type)?;
let mut total = Duration::from_millis(1000);
@@ -150,7 +151,7 @@ impl AnimeGif {
let frame_count = total.as_millis() / 30;
let single = AnimeFrame {
data: image.into_data_buffer(anime_type),
data: image.into_data_buffer(anime_type)?,
delay: Duration::from_millis(30),
};
let frames = vec![single; frame_count as usize];
@@ -169,7 +170,7 @@ impl AnimeGif {
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let mut frames = Vec::new();
let mut decoder = gif::DecodeOptions::new();
@@ -225,7 +226,7 @@ impl AnimeGif {
image.update();
frames.push(AnimeFrame {
data: <AnimeDataBuffer>::from(&image),
data: <AnimeDataBuffer>::try_from(&image)?,
delay: Duration::from_millis(wait as u64),
});
}
@@ -244,7 +245,7 @@ impl AnimeGif {
duration: AnimTime,
brightness: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let image =
AnimeImage::from_png(file_name, scale, angle, translation, brightness, anime_type)?;
@@ -259,7 +260,7 @@ impl AnimeGif {
let frame_count = total.as_millis() / 30;
let single = AnimeFrame {
data: <AnimeDataBuffer>::from(&image),
data: <AnimeDataBuffer>::try_from(&image)?,
delay: Duration::from_millis(30),
};
let frames = vec![single; frame_count as usize];

View File

@@ -1,4 +1,7 @@
use std::convert::TryFrom;
use crate::data::AnimeDataBuffer;
use crate::error::{AnimeError, Result};
use crate::{AnimeImage, AnimeType};
// TODO: Adjust these sizes as WIDTH_GA401 WIDTH_GA402
@@ -87,11 +90,12 @@ impl AnimeGrid {
// }
}
impl From<AnimeGrid> for AnimeDataBuffer {
impl TryFrom<AnimeGrid> for AnimeDataBuffer {
type Error = AnimeError;
/// Do conversion from the nested Vec in AniMeMatrix to the two required
/// packets suitable for sending over USB
#[inline]
fn from(anime: AnimeGrid) -> Self {
fn try_from(anime: AnimeGrid) -> Result<Self> {
let mut buf = vec![0u8; anime.anime_type.data_length()];
for (idx, pos) in AnimeImage::generate_image_positioning(anime.anime_type)
@@ -123,7 +127,7 @@ mod tests {
}
}
let matrix = <AnimeDataBuffer>::from(matrix);
let matrix = <AnimeDataBuffer>::try_from(matrix).unwrap();
let data_cmp = [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

View File

@@ -1,9 +1,13 @@
use std::path::Path;
use std::{convert::TryFrom, path::Path};
pub use glam::Vec2;
use glam::{Mat3, Vec3};
use crate::{data::AnimeDataBuffer, error::AnimeError, AnimeType};
use crate::{
data::AnimeDataBuffer,
error::{AnimeError, Result},
AnimeType,
};
/// A single greyscale + alpha pixel in the image
#[derive(Copy, Clone, Debug)]
@@ -83,7 +87,7 @@ impl AnimeImage {
pixels: Vec<Pixel>,
width: u32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
if bright < 0.0 || bright > 1.0 {
return Err(AnimeError::InvalidBrightness(bright));
}
@@ -388,7 +392,7 @@ impl AnimeImage {
translation: Vec2,
bright: f32,
anime_type: AnimeType,
) -> Result<Self, AnimeError> {
) -> Result<Self> {
let data = std::fs::read(path)?;
let data = std::io::Cursor::new(data);
let decoder = png_pong::Decoder::new(data)?.into_steps();
@@ -484,11 +488,12 @@ impl AnimeImage {
}
}
impl From<&AnimeImage> for AnimeDataBuffer {
impl TryFrom<&AnimeImage> for AnimeDataBuffer {
type Error = AnimeError;
/// Do conversion from the nested Vec in AnimeDataBuffer to the two required
/// packets suitable for sending over USB
#[inline]
fn from(leds: &AnimeImage) -> Self {
fn try_from(leds: &AnimeImage) -> Result<Self> {
let mut l: Vec<u8> = leds
.led_pos
.iter()
@@ -506,7 +511,7 @@ impl From<&AnimeImage> for AnimeDataBuffer {
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use std::{convert::TryFrom, path::PathBuf};
use crate::{image::*, AnimTime, AnimeGif, AnimePacketType};
@@ -734,8 +739,8 @@ mod tests {
)
.unwrap();
matrix._edge_outline();
let data = AnimeDataBuffer::from(&matrix);
let pkt = AnimePacketType::from(data);
let data = AnimeDataBuffer::try_from(&matrix).unwrap();
let pkt = AnimePacketType::try_from(data).unwrap();
assert_eq!(pkt[0], pkt0_check);
assert_eq!(pkt[1], pkt1_check);
@@ -759,6 +764,6 @@ mod tests {
)
.unwrap();
matrix.frames()[0].frame();
let _pkt = AnimePacketType::from(matrix.frames()[0].frame().clone());
let _pkt = AnimePacketType::try_from(matrix.frames()[0].frame().clone()).unwrap();
}
}

View File

@@ -1,10 +1,10 @@
use std::{path::PathBuf, time::Duration};
use glam::Vec2;
use serde_derive::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::{path::PathBuf, time::Duration};
use crate::{
error::AnimeError, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType,
error::Result, AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, AnimeType,
};
/// All the possible AniMe actions that can be used. This enum is intended to be
@@ -65,10 +65,7 @@ pub enum ActionData {
}
impl ActionData {
pub fn from_anime_action(
anime_type: AnimeType,
action: &ActionLoader,
) -> Result<ActionData, AnimeError> {
pub fn from_anime_action(anime_type: AnimeType, action: &ActionLoader) -> Result<ActionData> {
let a = match action {
ActionLoader::AsusAnimation {
file,
@@ -87,7 +84,7 @@ impl ActionData {
} => match time {
AnimTime::Infinite => {
let image = AnimeDiagonal::from_png(file, None, *brightness, anime_type)?;
let data = image.into_data_buffer(anime_type);
let data = image.into_data_buffer(anime_type)?;
ActionData::Image(Box::new(data))
}
_ => ActionData::Animation(AnimeGif::from_diagonal_png(
@@ -147,7 +144,7 @@ impl ActionData {
*brightness,
anime_type,
)?;
let data = <AnimeDataBuffer>::from(&image);
let data = <AnimeDataBuffer>::try_from(&image)?;
ActionData::Image(Box::new(data))
}
_ => ActionData::Animation(AnimeGif::from_png(
@@ -180,7 +177,7 @@ impl Sequences {
/// 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> {
pub fn insert(&mut self, index: usize, action: &ActionLoader) -> Result<()> {
self.0
.insert(index, ActionData::from_anime_action(self.1, action)?);
Ok(())