use std::sync::Arc;
use std::time::Duration;
use hidapi::{HidApi, HidResult};
use image::DynamicImage;
use tokio::sync::Mutex;
use tokio::task::block_in_place;
use tokio::time::sleep;
use crate::{AjazzError, AjazzInput, DeviceState, Event, Kind};
use crate::device::{handle_input_state_change, Ajazz};
use crate::hid::list_devices;
use crate::images::convert_image_async;
pub fn refresh_device_list_async(hidapi: &mut HidApi) -> HidResult<()> {
block_in_place(move || hidapi.refresh_devices())
}
pub fn list_devices_async(hidapi: &HidApi) -> Vec<(Kind, String)> {
block_in_place(move || list_devices(hidapi))
}
#[derive(Clone)]
pub struct AsyncAjazz {
kind: Kind,
device: Arc<Mutex<Ajazz>>,
}
impl AsyncAjazz {
pub fn connect(
hidapi: &HidApi,
kind: Kind,
serial: &str,
) -> Result<AsyncAjazz, AjazzError> {
let device = block_in_place(move || Ajazz::connect(hidapi, kind, serial))?;
Ok(AsyncAjazz {
kind,
device: Arc::new(Mutex::new(device)),
})
}
pub fn connect_with_retries(
hidapi: &HidApi,
kind: Kind,
serial: &str,
attempts: u8,
) -> Result<AsyncAjazz, AjazzError> {
let device = block_in_place(move || {
Ajazz::connect_with_retries(hidapi, kind, serial, attempts)
})?;
Ok(AsyncAjazz {
kind,
device: Arc::new(Mutex::new(device)),
})
}
}
impl AsyncAjazz {
pub fn kind(&self) -> Kind {
self.kind
}
pub async fn manufacturer(&self) -> Result<String, AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.manufacturer())
}
pub async fn product(&self) -> Result<String, AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.product())
}
pub async fn serial_number(&self) -> Result<String, AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.serial_number())
}
pub async fn firmware_version(&self) -> Result<String, AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.firmware_version())
}
pub async fn read_input(&self, poll_rate: f32) -> Result<AjazzInput, AjazzError> {
loop {
let device = self.device.lock().await;
let data = block_in_place(move || device.read_input(None))?;
if !data.is_empty() {
return Ok(data);
}
sleep(Duration::from_secs_f32(1.0 / poll_rate)).await;
}
}
pub async fn reset(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.reset())
}
pub async fn set_brightness(&self, percent: u8) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.set_brightness(percent))
}
pub async fn clear_button_image(&self, key: u8) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.clear_button_image(key))
}
pub async fn clear_all_button_images(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.clear_all_button_images())
}
pub async fn set_button_image(
&self,
key: u8,
image: DynamicImage,
) -> Result<(), AjazzError> {
let image = convert_image_async(self.kind, image)?;
let device = self.device.lock().await;
block_in_place(move || device.set_button_image_data(key, &image))
}
pub async fn set_button_image_data(
&self,
key: u8,
image_data: &[u8],
) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.set_button_image_data(key, image_data))
}
pub async fn set_logo_image(&self, image: DynamicImage) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.set_logo_image(image))
}
pub async fn sleep(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.sleep())
}
pub async fn keep_alive(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.keep_alive())
}
pub async fn shutdown(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.shutdown())
}
pub async fn flush(&self) -> Result<(), AjazzError> {
let device = self.device.lock().await;
block_in_place(move || device.flush())
}
pub fn get_reader(&self) -> Arc<AsyncDeviceStateReader> {
Arc::new(AsyncDeviceStateReader {
device: self.clone(),
states: Mutex::new(DeviceState {
buttons: vec![false; self.kind.key_count() as usize],
encoders: vec![false; self.kind.encoder_count() as usize],
}),
})
}
}
pub struct AsyncDeviceStateReader {
device: AsyncAjazz,
states: Mutex<DeviceState>,
}
impl AsyncDeviceStateReader {
pub async fn read(&self, poll_rate: f32) -> Result<Vec<Event>, AjazzError> {
let input = self.device.read_input(poll_rate).await?;
let mut current_state = self.states.lock().await;
let updates = handle_input_state_change(input, &mut current_state)?;
Ok(updates)
}
}