mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
anime: initial system config work
This commit is contained in:
@@ -4,66 +4,49 @@ use rog_anime::{
|
||||
pkt_for_apply, pkt_for_flush, pkt_for_set_boot, pkt_for_set_on, pkts_for_init, PROD_ID,
|
||||
VENDOR_ID,
|
||||
},
|
||||
AnimeDataBuffer, AnimePacketType,
|
||||
ActionData, AnimTime, AnimeDataBuffer, AnimePacketType, ANIME_DATA_LEN,
|
||||
};
|
||||
use rog_types::supported::AnimeSupportedFunctions;
|
||||
use rusb::{Device, DeviceHandle};
|
||||
use std::error::Error;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
error::Error,
|
||||
sync::{Arc, Mutex},
|
||||
thread::sleep,
|
||||
time::Instant,
|
||||
};
|
||||
use std::{sync::atomic::AtomicBool, time::Duration};
|
||||
use zbus::dbus_interface;
|
||||
use zvariant::ObjectPath;
|
||||
|
||||
use crate::GetSupported;
|
||||
use crate::{
|
||||
config_anime::{AnimeConfig, AnimeConfigCached},
|
||||
error::RogError,
|
||||
GetSupported,
|
||||
};
|
||||
|
||||
impl GetSupported for CtrlAnimeDisplay {
|
||||
impl GetSupported for CtrlAnime {
|
||||
type A = AnimeSupportedFunctions;
|
||||
|
||||
fn get_supported() -> Self::A {
|
||||
AnimeSupportedFunctions(CtrlAnimeDisplay::get_device(VENDOR_ID, PROD_ID).is_ok())
|
||||
AnimeSupportedFunctions(CtrlAnime::get_device(VENDOR_ID, PROD_ID).is_ok())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnimeDisplay {
|
||||
pub struct CtrlAnime {
|
||||
handle: DeviceHandle<rusb::GlobalContext>,
|
||||
cache: AnimeConfigCached,
|
||||
_config: AnimeConfig,
|
||||
// set to force thread to exit
|
||||
thread_exit: AtomicBool,
|
||||
// Set to false when the thread exits
|
||||
thread_running: AtomicBool,
|
||||
}
|
||||
|
||||
impl crate::ZbusAdd for CtrlAnimeDisplay {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlAnimeDisplay {
|
||||
/// Writes a data stream of length
|
||||
fn write(&self, input: AnimeDataBuffer) {
|
||||
self.write_data_buffer(input);
|
||||
}
|
||||
|
||||
fn set_on_off(&self, status: bool) {
|
||||
self.write_bytes(&pkt_for_set_on(status));
|
||||
}
|
||||
|
||||
fn set_boot_on_off(&self, on: bool) {
|
||||
self.write_bytes(&pkt_for_set_boot(on));
|
||||
self.write_bytes(&pkt_for_apply());
|
||||
}
|
||||
}
|
||||
|
||||
impl CtrlAnimeDisplay {
|
||||
impl CtrlAnime {
|
||||
#[inline]
|
||||
pub fn new() -> Result<CtrlAnimeDisplay, Box<dyn Error>> {
|
||||
pub fn new(config: AnimeConfig) -> Result<CtrlAnime, Box<dyn Error>> {
|
||||
// We don't expect this ID to ever change
|
||||
let device = CtrlAnimeDisplay::get_device(0x0b05, 0x193b)?;
|
||||
let device = CtrlAnime::get_device(0x0b05, 0x193b)?;
|
||||
|
||||
let mut device = device.open()?;
|
||||
device.reset()?;
|
||||
@@ -79,7 +62,16 @@ impl CtrlAnimeDisplay {
|
||||
})?;
|
||||
|
||||
info!("Device has an AniMe Matrix display");
|
||||
let ctrl = CtrlAnimeDisplay { handle: device };
|
||||
let mut cache = AnimeConfigCached::default();
|
||||
cache.init_from_config(&config)?;
|
||||
|
||||
let ctrl = CtrlAnime {
|
||||
handle: device,
|
||||
cache,
|
||||
_config: config,
|
||||
thread_exit: AtomicBool::new(false),
|
||||
thread_running: AtomicBool::new(false),
|
||||
};
|
||||
ctrl.do_initialization();
|
||||
|
||||
Ok(ctrl)
|
||||
@@ -95,6 +87,108 @@ impl CtrlAnimeDisplay {
|
||||
Err(rusb::Error::NoDevice)
|
||||
}
|
||||
|
||||
// DOUBLE THREAD NEST!
|
||||
fn run_thread(inner: Arc<Mutex<CtrlAnime>>, action: Option<ActionData>, mut once: bool) {
|
||||
std::thread::Builder::new()
|
||||
.name("AniMe system thread start".into())
|
||||
.spawn(move || {
|
||||
// Make the loop exit first
|
||||
loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
lock.thread_exit
|
||||
.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
if !lock
|
||||
.thread_running
|
||||
.load(std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
lock.thread_exit
|
||||
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
info!("AniMe system thread exited");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::thread::Builder::new()
|
||||
.name("AniMe system actions".into())
|
||||
.spawn(move || {
|
||||
info!("AniMe system thread started");
|
||||
'main: loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
if !once
|
||||
&& lock.thread_exit.load(std::sync::atomic::Ordering::SeqCst)
|
||||
{
|
||||
break 'main;
|
||||
}
|
||||
if let Some(ref action) = action {
|
||||
match action {
|
||||
ActionData::Animation(frames) => {
|
||||
let mut count = 0;
|
||||
let start = Instant::now();
|
||||
'animation: loop {
|
||||
for frame in frames.frames() {
|
||||
lock.write_data_buffer(frame.frame().clone());
|
||||
if let AnimTime::Time(time) = frames.duration()
|
||||
{
|
||||
if Instant::now().duration_since(start)
|
||||
> time
|
||||
{
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
sleep(frame.delay());
|
||||
}
|
||||
if let AnimTime::Cycles(times) = frames.duration() {
|
||||
count += 1;
|
||||
if count >= times {
|
||||
break 'animation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ActionData::Image(image) => {
|
||||
once = false;
|
||||
lock.write_data_buffer(image.as_ref().clone())
|
||||
}
|
||||
ActionData::Pause(_) => {}
|
||||
ActionData::AudioEq => {}
|
||||
ActionData::SystemInfo => {}
|
||||
ActionData::TimeDate => {}
|
||||
ActionData::Matrix => {}
|
||||
}
|
||||
} else {
|
||||
break 'main;
|
||||
}
|
||||
if once {
|
||||
let data =
|
||||
AnimeDataBuffer::from_vec([0u8; ANIME_DATA_LEN].to_vec());
|
||||
lock.write_data_buffer(data);
|
||||
break 'main;
|
||||
}
|
||||
}
|
||||
}
|
||||
'exit: loop {
|
||||
if let Ok(lock) = inner.try_lock() {
|
||||
lock.thread_exit
|
||||
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
lock.thread_running
|
||||
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
break 'exit;
|
||||
}
|
||||
}
|
||||
})
|
||||
.map(|err| info!("AniMe system thread: {:?}", err))
|
||||
.ok();
|
||||
})
|
||||
.map(|err| info!("AniMe system thread: {:?}", err))
|
||||
.ok();
|
||||
}
|
||||
|
||||
fn write_bytes(&self, message: &[u8]) {
|
||||
match self.handle.write_control(
|
||||
0x21, // request_type
|
||||
@@ -126,3 +220,89 @@ impl CtrlAnimeDisplay {
|
||||
self.write_bytes(&pkts[1]);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnimeTask(pub Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
impl crate::CtrlTask for CtrlAnimeTask {
|
||||
fn do_task(&self) -> Result<(), RogError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnimeReloader(pub Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
impl crate::Reloadable for CtrlAnimeReloader {
|
||||
fn reload(&mut self) -> Result<(), RogError> {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
let action = lock.cache.boot.clone();
|
||||
CtrlAnime::run_thread(self.0.clone(), action, true);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CtrlAnimeZbus(pub Arc<Mutex<CtrlAnime>>);
|
||||
|
||||
/// The struct with the main dbus methods requires this trait
|
||||
impl crate::ZbusAdd for CtrlAnimeZbus {
|
||||
fn add_to_server(self, server: &mut zbus::ObjectServer) {
|
||||
server
|
||||
.at(
|
||||
&ObjectPath::from_str_unchecked("/org/asuslinux/Anime"),
|
||||
self,
|
||||
)
|
||||
.map_err(|err| {
|
||||
warn!("CtrlAnimeDisplay: add_to_server {}", err);
|
||||
err
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
// None of these calls can be guarnateed to succeed unless we loop until okay
|
||||
// If the try_lock *does* succeed then any other thread trying to lock will not grab it
|
||||
// until we finish.
|
||||
#[dbus_interface(name = "org.asuslinux.Daemon")]
|
||||
impl CtrlAnimeZbus {
|
||||
/// Writes a data stream of length. Will force system thread to exit until it is restarted
|
||||
fn write(&self, input: AnimeDataBuffer) {
|
||||
'outer: loop {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
lock.thread_exit
|
||||
.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||
lock.write_data_buffer(input);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_on_off(&self, status: bool) {
|
||||
'outer: loop {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
lock.write_bytes(&pkt_for_set_on(status));
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_boot_on_off(&self, on: bool) {
|
||||
'outer: loop {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
lock.write_bytes(&pkt_for_set_boot(on));
|
||||
lock.write_bytes(&pkt_for_apply());
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run_main_loop(&self, on: bool) {
|
||||
'outer: loop {
|
||||
if let Ok(lock) = self.0.try_lock() {
|
||||
lock.thread_exit
|
||||
.store(on, std::sync::atomic::Ordering::SeqCst);
|
||||
CtrlAnime::run_thread(self.0.clone(), lock.cache.system.clone(), false);
|
||||
break 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user