hyperion/instance/device/
common.rs

1use std::time::Instant;
2
3use async_trait::async_trait;
4
5use super::{DeviceError, DeviceImpl};
6use crate::models::{self, DeviceConfig};
7
8#[async_trait]
9pub trait WritingDevice: Send + Sized {
10    type Config: DeviceConfig;
11
12    fn new(config: &Self::Config) -> Result<Self, DeviceError>;
13
14    async fn set_let_data(
15        &mut self,
16        config: &Self::Config,
17        led_data: &[models::Color],
18    ) -> Result<(), DeviceError>;
19
20    async fn write(&mut self) -> Result<(), DeviceError>;
21}
22
23pub struct Rewriter<D: WritingDevice> {
24    inner: D,
25    config: D::Config,
26    last_write_time: Option<Instant>,
27    next_write_time: Option<Instant>,
28}
29
30impl<D: WritingDevice> Rewriter<D> {
31    pub fn new(config: D::Config) -> Result<Self, DeviceError> {
32        let inner = D::new(&config)?;
33
34        Ok(Self {
35            inner,
36            config,
37            last_write_time: None,
38            next_write_time: None,
39        })
40    }
41
42    async fn write(&mut self) -> Result<(), DeviceError> {
43        self.inner.write().await?;
44        self.last_write_time = Some(Instant::now());
45        self.next_write_time = None;
46        Ok(())
47    }
48
49    async fn latching_write(&mut self) -> Result<(), DeviceError> {
50        let latch_time = self.config.latch_time();
51        if latch_time.is_zero() {
52            // No latch time, write immediately
53            self.write().await?;
54        } else if let Some(lwt) = self.last_write_time {
55            // We wrote something already, so schedule a write after the next latch period
56            let now = Instant::now();
57            let next_write_time = lwt + latch_time;
58
59            if next_write_time < now {
60                // Latch time elapsed already
61                self.write().await?;
62            } else {
63                // Not elapsed yet, so schedule it
64                self.next_write_time = Some(next_write_time);
65            }
66        } else {
67            // Never wrote anything, so immediately write
68            self.write().await?;
69        }
70
71        Ok(())
72    }
73}
74
75#[async_trait]
76impl<D: WritingDevice> DeviceImpl for Rewriter<D> {
77    async fn set_led_data(&mut self, led_data: &[models::Color]) -> Result<(), DeviceError> {
78        self.inner.set_let_data(&self.config, led_data).await?;
79        self.latching_write().await?;
80        Ok(())
81    }
82
83    async fn update(&mut self) -> Result<(), DeviceError> {
84        // Handle latching
85        if let Some(next_write_time) = self.next_write_time {
86            // A write was pending because of latching
87            let now = Instant::now();
88
89            if next_write_time > now {
90                // We still have to wait
91                tokio::time::sleep_until(next_write_time.into()).await;
92            }
93
94            // Elapsed, write immediately
95            self.write().await?;
96        }
97
98        if let Some(rewrite_time) = self.config.rewrite_time() {
99            let now = Instant::now();
100            let next_rewrite_time = self
101                .last_write_time
102                .map(|lwt| lwt + rewrite_time)
103                .unwrap_or(now);
104
105            // Wait until the next rewrite cycle if necessary
106            if next_rewrite_time > now {
107                tokio::time::sleep_until(next_rewrite_time.into()).await;
108            }
109
110            // Write to device
111            self.latching_write().await?;
112
113            Ok(())
114        } else {
115            futures::future::pending().await
116        }
117    }
118}