use std::{iter::zip, sync::Arc, time::Duration};
use tokio::sync::Mutex;
use crate::{device::Device, error::MirajazzError, types::DeviceInput};
#[derive(Copy, Clone, Debug, Hash)]
pub enum DeviceStateUpdate {
ButtonDown(u8),
ButtonUp(u8),
EncoderDown(u8),
EncoderUp(u8),
EncoderTwist(u8, i8),
}
#[derive(Default)]
pub struct DeviceState {
pub buttons: Vec<bool>,
pub encoders: Vec<bool>,
}
pub struct DeviceStateReader {
pub device: Arc<Device>,
pub states: Mutex<DeviceState>,
pub process_input: fn(u8, u8) -> Result<DeviceInput, MirajazzError>,
}
impl DeviceStateReader {
pub async fn read(
&self,
timeout: Option<Duration>,
) -> Result<Vec<DeviceStateUpdate>, MirajazzError> {
let input = self.device.read_input(timeout, self.process_input).await?;
Ok(self.input_to_updates(input).await)
}
async fn input_to_updates(&self, input: DeviceInput) -> Vec<DeviceStateUpdate> {
let mut my_states = self.states.lock().await;
let mut updates = vec![];
match input {
DeviceInput::ButtonStateChange(buttons) => {
for (index, (their, mine)) in
zip(buttons.iter(), my_states.buttons.iter()).enumerate()
{
if !self.device.supports_both_states() {
if *their {
updates.push(DeviceStateUpdate::ButtonDown(index as u8));
updates.push(DeviceStateUpdate::ButtonUp(index as u8));
}
} else if their != mine {
if *their {
updates.push(DeviceStateUpdate::ButtonDown(index as u8));
} else {
updates.push(DeviceStateUpdate::ButtonUp(index as u8));
}
}
}
my_states.buttons = buttons;
}
DeviceInput::EncoderStateChange(encoders) => {
for (index, (their, mine)) in
zip(encoders.iter(), my_states.encoders.iter()).enumerate()
{
if !self.device.supports_both_states() {
if *their {
updates.push(DeviceStateUpdate::EncoderDown(index as u8));
updates.push(DeviceStateUpdate::EncoderUp(index as u8));
}
} else if *their != *mine {
if *their {
updates.push(DeviceStateUpdate::EncoderDown(index as u8));
} else {
updates.push(DeviceStateUpdate::EncoderUp(index as u8));
}
}
}
my_states.encoders = encoders;
}
DeviceInput::EncoderTwist(twist) => {
for (index, change) in twist.iter().enumerate() {
if *change != 0 {
updates.push(DeviceStateUpdate::EncoderTwist(index as u8, *change));
}
}
}
_ => {}
}
drop(my_states);
updates
}
}