mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
First pass of Anime update for new matrix display
Co-authored with @I-Al-Istannen Part of #189
This commit is contained in:
@@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased ]
|
||||
|
||||
### Changed
|
||||
- Data for anime-matrix now requires passing the laptop model as enum
|
||||
|
||||
### Added
|
||||
- Support for GA503R LED modes
|
||||
### Changed
|
||||
|
||||
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1027,6 +1027,8 @@ dependencies = [
|
||||
"png_pong",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"sysfs-class",
|
||||
"udev",
|
||||
"zvariant",
|
||||
]
|
||||
|
||||
|
||||
@@ -7,122 +7,122 @@ use rog_dbus::RogDbusClientBlocking;
|
||||
fn main() {
|
||||
let (client, _) = RogDbusClientBlocking::new().unwrap();
|
||||
let mut matrix = AnimeDataBuffer::new();
|
||||
matrix.get_mut()[1] = 100; // start = 1
|
||||
for n in matrix.get_mut()[2..32].iter_mut() {
|
||||
matrix.data_mut()[1] = 100; // start = 1
|
||||
for n in matrix.data_mut()[2..32].iter_mut() {
|
||||
*n = 250;
|
||||
}
|
||||
matrix.get_mut()[32] = 100; // end
|
||||
matrix.get_mut()[34] = 100; // start x = 0
|
||||
matrix.get_mut()[66] = 100; // end
|
||||
matrix.get_mut()[69] = 100; // start x = 1
|
||||
matrix.get_mut()[101] = 100; // end
|
||||
matrix.get_mut()[102] = 100; // start
|
||||
matrix.get_mut()[134] = 100; // end
|
||||
matrix.get_mut()[137] = 100; // start
|
||||
matrix.get_mut()[169] = 100; // end
|
||||
matrix.get_mut()[170] = 100; // start
|
||||
matrix.get_mut()[202] = 100; // end
|
||||
matrix.get_mut()[204] = 100; // start
|
||||
matrix.get_mut()[236] = 100; // end
|
||||
matrix.get_mut()[237] = 100; // start
|
||||
matrix.get_mut()[268] = 100; // end
|
||||
matrix.get_mut()[270] = 100; // start
|
||||
matrix.get_mut()[301] = 100; // end
|
||||
matrix.get_mut()[302] = 100; // start
|
||||
matrix.get_mut()[332] = 100; // end
|
||||
matrix.get_mut()[334] = 100; // start
|
||||
matrix.get_mut()[364] = 100; // end
|
||||
matrix.get_mut()[365] = 100; // start
|
||||
matrix.get_mut()[394] = 100; // end
|
||||
matrix.get_mut()[396] = 100; // start
|
||||
matrix.get_mut()[425] = 100; // end
|
||||
matrix.get_mut()[426] = 100; // start
|
||||
matrix.get_mut()[454] = 100; // end
|
||||
matrix.get_mut()[456] = 100; // start
|
||||
matrix.get_mut()[484] = 100; // end
|
||||
matrix.get_mut()[485] = 100; // start
|
||||
matrix.get_mut()[512] = 100; // end
|
||||
matrix.get_mut()[514] = 100; // start
|
||||
matrix.get_mut()[541] = 100; // end
|
||||
matrix.get_mut()[542] = 100; // start
|
||||
matrix.get_mut()[568] = 100; // end
|
||||
matrix.get_mut()[570] = 100; // start
|
||||
matrix.get_mut()[596] = 100; // end
|
||||
matrix.get_mut()[597] = 100; // start
|
||||
matrix.get_mut()[622] = 100; // end
|
||||
matrix.get_mut()[624] = 100; // start
|
||||
matrix.get_mut()[649] = 100; // end
|
||||
matrix.get_mut()[650] = 100; // start
|
||||
matrix.get_mut()[674] = 100; // end
|
||||
matrix.get_mut()[676] = 100; // start
|
||||
matrix.get_mut()[700] = 100; // end
|
||||
matrix.get_mut()[701] = 100; // start
|
||||
matrix.get_mut()[724] = 100; // end
|
||||
matrix.get_mut()[726] = 100; // start
|
||||
matrix.get_mut()[749] = 100; // end
|
||||
matrix.get_mut()[750] = 100; // start
|
||||
matrix.get_mut()[772] = 100; // end
|
||||
matrix.get_mut()[774] = 100; // start
|
||||
matrix.get_mut()[796] = 100; // end
|
||||
matrix.get_mut()[797] = 100; // start
|
||||
matrix.get_mut()[818] = 100; // end
|
||||
matrix.get_mut()[820] = 100; // start
|
||||
matrix.get_mut()[841] = 100; // end
|
||||
matrix.get_mut()[842] = 100; // start
|
||||
matrix.get_mut()[862] = 100; // end
|
||||
matrix.get_mut()[864] = 100; // start
|
||||
matrix.get_mut()[884] = 100; // end
|
||||
matrix.get_mut()[885] = 100; // start
|
||||
matrix.get_mut()[904] = 100; // end
|
||||
matrix.get_mut()[906] = 100; // start
|
||||
matrix.get_mut()[925] = 100; // end
|
||||
matrix.get_mut()[926] = 100; // start
|
||||
matrix.get_mut()[944] = 100; // end
|
||||
matrix.get_mut()[946] = 100; // start
|
||||
matrix.get_mut()[964] = 100; // end
|
||||
matrix.get_mut()[965] = 100; // start
|
||||
matrix.get_mut()[982] = 100; // end
|
||||
matrix.get_mut()[984] = 100; // start
|
||||
matrix.get_mut()[1001] = 100; // end
|
||||
matrix.get_mut()[1002] = 100; // start
|
||||
matrix.get_mut()[1018] = 100; // end
|
||||
matrix.get_mut()[1020] = 100; // start
|
||||
matrix.get_mut()[1036] = 100; // end
|
||||
matrix.get_mut()[1037] = 100; // start
|
||||
matrix.get_mut()[1052] = 100; // end
|
||||
matrix.get_mut()[1054] = 100; // start
|
||||
matrix.get_mut()[1069] = 100; // end
|
||||
matrix.get_mut()[1070] = 100; // start
|
||||
matrix.get_mut()[1084] = 100; // end
|
||||
matrix.get_mut()[1086] = 100; // start
|
||||
matrix.get_mut()[1100] = 100; // end
|
||||
matrix.get_mut()[1101] = 100; // start
|
||||
matrix.get_mut()[1114] = 100; // end
|
||||
matrix.get_mut()[1116] = 100; // start
|
||||
matrix.get_mut()[1129] = 100; // end
|
||||
matrix.get_mut()[1130] = 100; // start
|
||||
matrix.get_mut()[1142] = 100; // end
|
||||
matrix.get_mut()[1144] = 100; // start
|
||||
matrix.get_mut()[1156] = 100; // end
|
||||
matrix.get_mut()[1157] = 100; // start
|
||||
matrix.get_mut()[1168] = 100; // end
|
||||
matrix.get_mut()[1170] = 100; // start
|
||||
matrix.get_mut()[1181] = 100; // end
|
||||
matrix.get_mut()[1182] = 100; // start
|
||||
matrix.get_mut()[1192] = 100; // end
|
||||
matrix.get_mut()[1194] = 100; // start
|
||||
matrix.get_mut()[1204] = 100; // end
|
||||
matrix.get_mut()[1205] = 100; // start
|
||||
matrix.get_mut()[1214] = 100; // end
|
||||
matrix.get_mut()[1216] = 100; // start
|
||||
matrix.get_mut()[1225] = 100; // end
|
||||
matrix.get_mut()[1226] = 100; // start
|
||||
matrix.get_mut()[1234] = 100; // end
|
||||
matrix.get_mut()[1236] = 100; // start
|
||||
for n in matrix.get_mut()[1237..1244].iter_mut() {
|
||||
matrix.data_mut()[32] = 100; // end
|
||||
matrix.data_mut()[34] = 100; // start x = 0
|
||||
matrix.data_mut()[66] = 100; // end
|
||||
matrix.data_mut()[69] = 100; // start x = 1
|
||||
matrix.data_mut()[101] = 100; // end
|
||||
matrix.data_mut()[102] = 100; // start
|
||||
matrix.data_mut()[134] = 100; // end
|
||||
matrix.data_mut()[137] = 100; // start
|
||||
matrix.data_mut()[169] = 100; // end
|
||||
matrix.data_mut()[170] = 100; // start
|
||||
matrix.data_mut()[202] = 100; // end
|
||||
matrix.data_mut()[204] = 100; // start
|
||||
matrix.data_mut()[236] = 100; // end
|
||||
matrix.data_mut()[237] = 100; // start
|
||||
matrix.data_mut()[268] = 100; // end
|
||||
matrix.data_mut()[270] = 100; // start
|
||||
matrix.data_mut()[301] = 100; // end
|
||||
matrix.data_mut()[302] = 100; // start
|
||||
matrix.data_mut()[332] = 100; // end
|
||||
matrix.data_mut()[334] = 100; // start
|
||||
matrix.data_mut()[364] = 100; // end
|
||||
matrix.data_mut()[365] = 100; // start
|
||||
matrix.data_mut()[394] = 100; // end
|
||||
matrix.data_mut()[396] = 100; // start
|
||||
matrix.data_mut()[425] = 100; // end
|
||||
matrix.data_mut()[426] = 100; // start
|
||||
matrix.data_mut()[454] = 100; // end
|
||||
matrix.data_mut()[456] = 100; // start
|
||||
matrix.data_mut()[484] = 100; // end
|
||||
matrix.data_mut()[485] = 100; // start
|
||||
matrix.data_mut()[512] = 100; // end
|
||||
matrix.data_mut()[514] = 100; // start
|
||||
matrix.data_mut()[541] = 100; // end
|
||||
matrix.data_mut()[542] = 100; // start
|
||||
matrix.data_mut()[568] = 100; // end
|
||||
matrix.data_mut()[570] = 100; // start
|
||||
matrix.data_mut()[596] = 100; // end
|
||||
matrix.data_mut()[597] = 100; // start
|
||||
matrix.data_mut()[622] = 100; // end
|
||||
matrix.data_mut()[624] = 100; // start
|
||||
matrix.data_mut()[649] = 100; // end
|
||||
matrix.data_mut()[650] = 100; // start
|
||||
matrix.data_mut()[674] = 100; // end
|
||||
matrix.data_mut()[676] = 100; // start
|
||||
matrix.data_mut()[700] = 100; // end
|
||||
matrix.data_mut()[701] = 100; // start
|
||||
matrix.data_mut()[724] = 100; // end
|
||||
matrix.data_mut()[726] = 100; // start
|
||||
matrix.data_mut()[749] = 100; // end
|
||||
matrix.data_mut()[750] = 100; // start
|
||||
matrix.data_mut()[772] = 100; // end
|
||||
matrix.data_mut()[774] = 100; // start
|
||||
matrix.data_mut()[796] = 100; // end
|
||||
matrix.data_mut()[797] = 100; // start
|
||||
matrix.data_mut()[818] = 100; // end
|
||||
matrix.data_mut()[820] = 100; // start
|
||||
matrix.data_mut()[841] = 100; // end
|
||||
matrix.data_mut()[842] = 100; // start
|
||||
matrix.data_mut()[862] = 100; // end
|
||||
matrix.data_mut()[864] = 100; // start
|
||||
matrix.data_mut()[884] = 100; // end
|
||||
matrix.data_mut()[885] = 100; // start
|
||||
matrix.data_mut()[904] = 100; // end
|
||||
matrix.data_mut()[906] = 100; // start
|
||||
matrix.data_mut()[925] = 100; // end
|
||||
matrix.data_mut()[926] = 100; // start
|
||||
matrix.data_mut()[944] = 100; // end
|
||||
matrix.data_mut()[946] = 100; // start
|
||||
matrix.data_mut()[964] = 100; // end
|
||||
matrix.data_mut()[965] = 100; // start
|
||||
matrix.data_mut()[982] = 100; // end
|
||||
matrix.data_mut()[984] = 100; // start
|
||||
matrix.data_mut()[1001] = 100; // end
|
||||
matrix.data_mut()[1002] = 100; // start
|
||||
matrix.data_mut()[1018] = 100; // end
|
||||
matrix.data_mut()[1020] = 100; // start
|
||||
matrix.data_mut()[1036] = 100; // end
|
||||
matrix.data_mut()[1037] = 100; // start
|
||||
matrix.data_mut()[1052] = 100; // end
|
||||
matrix.data_mut()[1054] = 100; // start
|
||||
matrix.data_mut()[1069] = 100; // end
|
||||
matrix.data_mut()[1070] = 100; // start
|
||||
matrix.data_mut()[1084] = 100; // end
|
||||
matrix.data_mut()[1086] = 100; // start
|
||||
matrix.data_mut()[1100] = 100; // end
|
||||
matrix.data_mut()[1101] = 100; // start
|
||||
matrix.data_mut()[1114] = 100; // end
|
||||
matrix.data_mut()[1116] = 100; // start
|
||||
matrix.data_mut()[1129] = 100; // end
|
||||
matrix.data_mut()[1130] = 100; // start
|
||||
matrix.data_mut()[1142] = 100; // end
|
||||
matrix.data_mut()[1144] = 100; // start
|
||||
matrix.data_mut()[1156] = 100; // end
|
||||
matrix.data_mut()[1157] = 100; // start
|
||||
matrix.data_mut()[1168] = 100; // end
|
||||
matrix.data_mut()[1170] = 100; // start
|
||||
matrix.data_mut()[1181] = 100; // end
|
||||
matrix.data_mut()[1182] = 100; // start
|
||||
matrix.data_mut()[1192] = 100; // end
|
||||
matrix.data_mut()[1194] = 100; // start
|
||||
matrix.data_mut()[1204] = 100; // end
|
||||
matrix.data_mut()[1205] = 100; // start
|
||||
matrix.data_mut()[1214] = 100; // end
|
||||
matrix.data_mut()[1216] = 100; // start
|
||||
matrix.data_mut()[1225] = 100; // end
|
||||
matrix.data_mut()[1226] = 100; // start
|
||||
matrix.data_mut()[1234] = 100; // end
|
||||
matrix.data_mut()[1236] = 100; // start
|
||||
for n in matrix.data_mut()[1237..1244].iter_mut() {
|
||||
*n = 250;
|
||||
}
|
||||
matrix.get_mut()[1244] = 100; // end
|
||||
matrix.data_mut()[1244] = 100; // end
|
||||
println!("{:?}", &matrix);
|
||||
|
||||
client.proxies().anime().write(matrix).unwrap();
|
||||
|
||||
@@ -7,6 +7,7 @@ use gumdrop::{Opt, Options};
|
||||
|
||||
use anime_cli::{AnimeActions, AnimeCommand};
|
||||
use profiles_cli::{FanCurveCommand, ProfileCommand};
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_anime::{AnimTime, AnimeDataBuffer, AnimeDiagonal, AnimeGif, AnimeImage, Vec2};
|
||||
use rog_aura::usb::AuraControl;
|
||||
use rog_aura::{self, AuraEffect};
|
||||
@@ -234,6 +235,7 @@ fn handle_anime(
|
||||
dbus.proxies().anime().set_brightness(bright as f32)?
|
||||
}
|
||||
if let Some(action) = cmd.command.as_ref() {
|
||||
let anime_type = get_anime_type()?;
|
||||
match action {
|
||||
AnimeActions::Image(image) => {
|
||||
if image.help_requested() || image.path.is_empty() {
|
||||
@@ -250,6 +252,7 @@ fn handle_anime(
|
||||
image.angle,
|
||||
Vec2::new(image.x_pos, image.y_pos),
|
||||
image.bright,
|
||||
anime_type,
|
||||
)?;
|
||||
|
||||
dbus.proxies()
|
||||
@@ -269,7 +272,7 @@ fn handle_anime(
|
||||
|
||||
dbus.proxies()
|
||||
.anime()
|
||||
.write(<AnimeDataBuffer>::from(&matrix))?;
|
||||
.write(matrix.into_data_buffer(anime_type))?;
|
||||
}
|
||||
AnimeActions::Gif(gif) => {
|
||||
if gif.help_requested() || gif.path.is_empty() {
|
||||
@@ -287,6 +290,7 @@ fn handle_anime(
|
||||
Vec2::new(gif.x_pos, gif.y_pos),
|
||||
AnimTime::Count(1),
|
||||
gif.bright,
|
||||
anime_type,
|
||||
)?;
|
||||
|
||||
let mut loops = gif.loops as i32;
|
||||
@@ -316,6 +320,7 @@ fn handle_anime(
|
||||
Path::new(&gif.path),
|
||||
AnimTime::Count(1),
|
||||
gif.bright,
|
||||
anime_type,
|
||||
)?;
|
||||
|
||||
let mut loops = gif.loops as i32;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use rog_anime::usb::get_anime_type;
|
||||
use rog_dbus::RogDbusClientBlocking;
|
||||
use rog_user::{
|
||||
ctrl_anime::{CtrlAnime, CtrlAnimeInner},
|
||||
@@ -28,8 +29,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let early_return = Arc::new(AtomicBool::new(false));
|
||||
// Set up the anime data and run loop/thread
|
||||
if supported.anime_ctrl.0 {
|
||||
let anime_type = get_anime_type()?;
|
||||
let anime_config = UserAnimeConfig::load_config(config.active_anime)?;
|
||||
let anime = anime_config.create_anime()?;
|
||||
let anime = anime_config.create_anime(anime_type)?;
|
||||
let anime_config = Arc::new(Mutex::new(anime_config));
|
||||
|
||||
executor
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use rog_anime::{ActionLoader, AnimTime, Fade, Sequences, Vec2};
|
||||
use rog_anime::{ActionLoader, AnimTime, AnimeType, Fade, Sequences, Vec2};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::error::Error;
|
||||
@@ -16,8 +16,8 @@ pub struct UserAnimeConfig {
|
||||
}
|
||||
|
||||
impl UserAnimeConfig {
|
||||
pub fn create_anime(&self) -> Result<Sequences, Error> {
|
||||
let mut seq = Sequences::new();
|
||||
pub fn create_anime(&self, anime_type: AnimeType) -> Result<Sequences, Error> {
|
||||
let mut seq = Sequences::new(anime_type);
|
||||
|
||||
for (idx, action) in self.anime.iter().enumerate() {
|
||||
seq.insert(idx, action)?;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::VERSION;
|
||||
use log::{error, info, warn};
|
||||
use rog_anime::Fade;
|
||||
use rog_anime::{error::AnimeError, ActionData, ActionLoader, AnimTime, Vec2};
|
||||
use rog_anime::{AnimeType, Fade};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
@@ -81,27 +81,28 @@ pub struct AnimeConfigCached {
|
||||
|
||||
impl AnimeConfigCached {
|
||||
pub fn init_from_config(&mut self, config: &AnimeConfig) -> Result<(), AnimeError> {
|
||||
let anime_type = AnimeType::GA401; // TODO: detect
|
||||
let mut sys = Vec::with_capacity(config.system.len());
|
||||
for ani in config.system.iter() {
|
||||
sys.push(ActionData::from_anime_action(ani)?);
|
||||
sys.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.system = sys;
|
||||
|
||||
let mut boot = Vec::with_capacity(config.boot.len());
|
||||
for ani in config.boot.iter() {
|
||||
boot.push(ActionData::from_anime_action(ani)?);
|
||||
boot.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.boot = boot;
|
||||
|
||||
let mut wake = Vec::with_capacity(config.wake.len());
|
||||
for ani in config.wake.iter() {
|
||||
wake.push(ActionData::from_anime_action(ani)?);
|
||||
wake.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.wake = wake;
|
||||
|
||||
let mut shutdown = Vec::with_capacity(config.shutdown.len());
|
||||
for ani in config.shutdown.iter() {
|
||||
shutdown.push(ActionData::from_anime_action(ani)?);
|
||||
shutdown.push(ActionData::from_anime_action(anime_type, ani)?);
|
||||
}
|
||||
self.shutdown = shutdown;
|
||||
Ok(())
|
||||
|
||||
@@ -8,10 +8,11 @@ use logind_zbus::manager::ManagerProxy;
|
||||
use rog_anime::{
|
||||
error::AnimeError,
|
||||
usb::{
|
||||
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
|
||||
VENDOR_ID,
|
||||
find_node, get_anime_type, pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on,
|
||||
pkts_for_init, PROD_ID, VENDOR_ID,
|
||||
},
|
||||
ActionData, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN,
|
||||
ActionData, AnimeDataBuffer, AnimePacketType, AnimeType, ANIME_GA401_DATA_LEN,
|
||||
ANIME_GA402_DATA_LEN,
|
||||
};
|
||||
use rog_supported::AnimeSupportedFunctions;
|
||||
use rusb::{Device, DeviceHandle};
|
||||
@@ -41,6 +42,7 @@ impl GetSupported for CtrlAnime {
|
||||
|
||||
pub struct CtrlAnime {
|
||||
_node: String,
|
||||
anime_type: AnimeType,
|
||||
handle: RefCell<DeviceHandle<rusb::GlobalContext>>,
|
||||
cache: AnimeConfigCached,
|
||||
config: AnimeConfig,
|
||||
@@ -53,7 +55,8 @@ pub struct CtrlAnime {
|
||||
impl CtrlAnime {
|
||||
#[inline]
|
||||
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, Box<dyn Error>> {
|
||||
let node = Self::find_node("193b")?;
|
||||
let node = find_node("193b")?;
|
||||
let anime_type = get_anime_type()?;
|
||||
let device = Self::get_dev_handle()?;
|
||||
|
||||
info!("Device has an AniMe Matrix display");
|
||||
@@ -62,6 +65,7 @@ impl CtrlAnime {
|
||||
|
||||
let ctrl = CtrlAnime {
|
||||
_node: node,
|
||||
anime_type,
|
||||
handle: RefCell::new(device),
|
||||
cache,
|
||||
config,
|
||||
@@ -73,34 +77,6 @@ impl CtrlAnime {
|
||||
Ok(ctrl)
|
||||
}
|
||||
|
||||
fn find_node(id_product: &str) -> Result<String, RogError> {
|
||||
let mut enumerator = udev::Enumerator::new().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("enumerator failed".into(), err)
|
||||
})?;
|
||||
enumerator.match_subsystem("usb").map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::Udev("match_subsystem failed".into(), err)
|
||||
})?;
|
||||
|
||||
for device in enumerator.scan_devices().map_err(|err| {
|
||||
warn!("{}", err);
|
||||
RogError::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() {
|
||||
info!("Using device at: {:?} for AniMe control", dev_node);
|
||||
return Ok(dev_node.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(RogError::MissingFunction(
|
||||
"ASUS AniMe device node not found".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn get_dev_handle() -> Result<DeviceHandle<rusb::GlobalContext>, Box<dyn Error>> {
|
||||
// We don't expect this ID to ever change
|
||||
let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
|
||||
@@ -156,10 +132,12 @@ impl CtrlAnime {
|
||||
// we don't block other threads/main
|
||||
let thread_exit;
|
||||
let thread_running;
|
||||
let anime_type;
|
||||
loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
thread_exit = lock.thread_exit.clone();
|
||||
thread_running = lock.thread_running.clone();
|
||||
anime_type = lock.anime_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -224,7 +202,16 @@ impl CtrlAnime {
|
||||
}
|
||||
// Clear the display on exit
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
let data = AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec());
|
||||
let data = match anime_type {
|
||||
AnimeType::GA401 => AnimeDataBuffer::from_vec(
|
||||
anime_type,
|
||||
[0u8; ANIME_GA401_DATA_LEN].to_vec(),
|
||||
),
|
||||
AnimeType::GA402 => AnimeDataBuffer::from_vec(
|
||||
anime_type,
|
||||
[0u8; ANIME_GA402_DATA_LEN].to_vec(),
|
||||
),
|
||||
};
|
||||
lock.write_data_buffer(data);
|
||||
}
|
||||
// Loop ended, set the atmonics
|
||||
@@ -277,7 +264,7 @@ impl CtrlAnime {
|
||||
/// Write only a data packet. This will modify the leds brightness using the
|
||||
/// global brightness set in config.
|
||||
fn write_data_buffer(&self, mut buffer: AnimeDataBuffer) {
|
||||
for led in buffer.get_mut()[7..].iter_mut() {
|
||||
for led in buffer.data_mut()[7..].iter_mut() {
|
||||
let mut bright = *led as f32 * self.config.brightness;
|
||||
if bright > 254.0 {
|
||||
bright = 254.0;
|
||||
|
||||
@@ -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 }
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
BIN
rog-anime/test/ga401-diagonal.gif
Normal file
BIN
rog-anime/test/ga401-diagonal.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 981 B |
BIN
rog-anime/test/ga401-diagonal.png
Normal file
BIN
rog-anime/test/ga401-diagonal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.0 KiB |
BIN
rog-anime/test/ga402-diagonal.gif
Normal file
BIN
rog-anime/test/ga402-diagonal.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 189 B |
BIN
rog-anime/test/ga402-diagonal.png
Normal file
BIN
rog-anime/test/ga402-diagonal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 670 B |
Reference in New Issue
Block a user