ble_ledly/capability/
sw_animate.rs

1use super::brightness::BrightnessOption;
2use crate::capability::color::ColorOption;
3use crate::communication_protocol::Protocol;
4use crate::device::Device;
5use crate::device::Write;
6use crate::error::{BluetoothError};
7use async_trait::async_trait;
8
9use std::time::Duration;
10use tokio::time;
11
12//---------//
13// animate //
14//---------//
15pub enum SWAnimateOption<'e> {
16    Breathing(&'e ColorOption, &'e SWAnimationRepeat, &'e SWAnimationSpeed),
17}
18
19pub enum SWAnimationRepeat {
20    FiniteCount(i32),
21    InfiniteCount,
22}
23
24pub enum SWAnimationSpeed {
25    Slowest,
26    Slower,
27    Slow,
28    Normal,
29    Fast,
30    Faster,
31    Fastest,
32}
33//--------------------//
34// Enum value mapping //
35//--------------------//
36fn sw_animation_speed(speed: &SWAnimationSpeed) -> u64 {
37    match speed {
38        SWAnimationSpeed::Fastest => 5,
39        SWAnimationSpeed::Faster => 20,
40        SWAnimationSpeed::Fast => 50,
41        SWAnimationSpeed::Normal => 200,
42        SWAnimationSpeed::Slow => 300,
43        SWAnimationSpeed::Slower => 400,
44        SWAnimationSpeed::Slowest => 600,
45    }
46}
47
48#[async_trait]
49pub trait SWAnimate {
50    async fn set<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
51        &self,
52        protocol: &'e P,
53        option: &'e SWAnimateOption,
54    ) -> Result<(), BluetoothError>;
55    async fn _breathing<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
56        &self,
57        protocol: &'e P,
58        color: &'e ColorOption,
59        interval: u64,
60    ) -> Result<(), BluetoothError>;
61    async fn breathing<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
62        &self,
63        protocol: &'e P,
64        color: &'e ColorOption,
65        repeat: &'e SWAnimationRepeat,
66        speed: &'e SWAnimationSpeed,
67    ) -> Result<(), BluetoothError>;
68}
69
70//-------------------------//
71// Blanket implementations //
72//-------------------------//
73#[async_trait]
74impl<D: Device + std::marker::Sync> SWAnimate for D {
75    // bound type to be transferred across threads
76    async fn set<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
77        &self,
78        protocol: &'e P,
79        option: &'e SWAnimateOption,
80    ) -> Result<(), BluetoothError> {
81        match option {
82            SWAnimateOption::Breathing(color, repeat, speed) => {
83                self.breathing(protocol, color, repeat, speed).await?;
84            }
85        }
86        Ok(())
87    }
88
89    //------------//
90    // Animations //
91    //------------//
92    // TODO: Implement exponential fading
93    async fn _breathing<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
94        &self,
95        protocol: &'e P,
96        color: &'e ColorOption,
97        interval: u64,
98    ) -> Result<(), BluetoothError> {
99        // TODO: replace loops with sine impl.
100        for i in 0..=100 {
101            let e_bytes = protocol.brightness(&BrightnessOption::LevelWithColor(
102                i as f32 / 100 as f32,
103                color,
104            ));
105            self.push(&(e_bytes)[..]).await?;
106            time::sleep(Duration::from_millis(interval)).await;
107        }
108        for i in (0..=100).rev() {
109            let e_bytes = protocol.brightness(&BrightnessOption::LevelWithColor(
110                i as f32 / 100 as f32,
111                color,
112            ));
113            self.push(&(e_bytes)[..]).await?;
114            time::sleep(Duration::from_millis(interval)).await;
115        }
116        Ok(())
117    }
118
119    async fn breathing<'e, P: Protocol + std::marker::Send + std::marker::Sync>(
120        &self,
121        protocol: &'e P,
122        color: &'e ColorOption,
123        repeat: &'e SWAnimationRepeat,
124        speed: &'e SWAnimationSpeed,
125    ) -> Result<(), BluetoothError> {
126        match repeat {
127            SWAnimationRepeat::FiniteCount(count) => {
128                let mut i = 0;
129                while i < *count {
130                    self._breathing(protocol, &color, sw_animation_speed(speed))
131                        .await?;
132                    i += 1;
133                }
134            }
135            SWAnimationRepeat::InfiniteCount => loop {
136                self._breathing(protocol, &color, sw_animation_speed(speed))
137                    .await?;
138            },
139        }
140        Ok(())
141    }
142}