use std::iter::zip;
use std::sync::Arc;
use std::time::Duration;
use hidapi::HidApi;
use image::DynamicImage;
use tokio::sync::Mutex;
use tokio::time::sleep;
use crate::{Kind, StreamDeck, StreamDeckError};
use crate::images::convert_image_async;
pub struct AsyncStreamDeck {
kind: Kind,
device: Mutex<StreamDeck>
}
impl AsyncStreamDeck {
pub fn connect(hidapi: &HidApi, kind: Kind, serial: &str) -> Result<Arc<AsyncStreamDeck>, StreamDeckError> {
let device = StreamDeck::connect(hidapi, kind, serial)?;
Ok(Arc::new(AsyncStreamDeck {
kind,
device: Mutex::new(device)
}))
}
}
impl AsyncStreamDeck {
pub fn kind(&self) -> Kind {
self.kind
}
pub async fn manufacturer(&self) -> Result<String, StreamDeckError> {
Ok(self.device.lock().await.manufacturer()?)
}
pub async fn product(&self) -> Result<String, StreamDeckError> {
Ok(self.device.lock().await.product()?)
}
pub async fn serial_number(&self) -> Result<String, StreamDeckError> {
Ok(self.device.lock().await.serial_number()?)
}
pub async fn firmware_version(&self) -> Result<String, StreamDeckError> {
Ok(self.device.lock().await.firmware_version()?)
}
pub async fn read_button_states(&self, poll_rate: f32) -> Result<Vec<bool>, StreamDeckError> {
loop {
let data = self.device.lock().await.read_button_states(None)?;
if !data.is_empty() {
return Ok(data);
}
sleep(Duration::from_secs_f32(1.0 / poll_rate)).await;
}
}
pub fn get_reader(self: &Arc<Self>) -> Arc<ButtonStateReader> {
Arc::new(ButtonStateReader {
device: self.clone(),
states: Mutex::new(vec![false; self.kind.key_count() as usize])
})
}
pub async fn reset(&self) -> Result<(), StreamDeckError> {
Ok(self.device.lock().await.reset()?)
}
pub async fn set_brightness(&self, percent: u8) -> Result<(), StreamDeckError> {
Ok(self.device.lock().await.set_brightness(percent)?)
}
pub async fn write_image(&self, key: u8, image_data: &[u8]) -> Result<(), StreamDeckError> {
Ok(self.device.lock().await.write_image(key, image_data)?)
}
pub async fn clear_button_image(&self, key: u8) -> Result<(), StreamDeckError> {
Ok(self.device.lock().await.write_image(key, &self.kind.blank_image())?)
}
pub async fn set_button_image(&self, key: u8, image: DynamicImage) -> Result<(), StreamDeckError> {
let image = convert_image_async(self.kind, image).await?;
Ok(self.device.lock().await.write_image(key, &image)?)
}
}
pub struct ButtonStateReader {
device: Arc<AsyncStreamDeck>,
states: Mutex<Vec<bool>>
}
#[derive(Copy, Clone, Debug, Hash)]
pub enum ButtonStateUpdate {
ButtonDown(u8),
ButtonUp(u8)
}
impl ButtonStateReader {
#[async_recursion::async_recursion]
pub async fn read(&self, poll_rate: f32) -> Result<Vec<ButtonStateUpdate>, StreamDeckError> {
let states = self.device.read_button_states(poll_rate).await?;
let mut my_states = self.states.lock().await;
let mut updates = vec![];
for (index, (their, mine)) in zip(states.iter(), my_states.iter()).enumerate() {
if *their != *mine {
if *their {
updates.push(ButtonStateUpdate::ButtonDown(index as u8));
} else {
updates.push(ButtonStateUpdate::ButtonUp(index as u8));
}
}
}
*my_states = states;
drop(my_states);
if updates.is_empty() {
self.read(poll_rate).await
} else {
Ok(updates)
}
}
}