timed_signal/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(test), no_std)]
3
4/// Signal state and scheduled tick action.
5#[derive(Debug, Default, Clone, PartialEq, Eq)]
6pub struct TimedSignal {
7    /// Current state, false = off, true = on.
8    state: bool,
9
10    /// Timed action.
11    tick_action: TickAction,
12
13    /// Invert state.
14    inverted: bool,
15}
16
17/// Action to perform when update() is called on a specific tick.
18#[derive(Debug, Default, Clone, PartialEq, Eq)]
19enum TickAction {
20    /// No action.
21    #[default]
22    None,
23
24    /// Set a state when tick is reached.
25    Set(u64, bool),
26
27    /// Set a state for a number of ticks.
28    /// This is a temporary state and will be changed to `Set` within `update()`.
29    SetFor(u64, bool),
30
31    /// Blink with given period.
32    Blink(u32),
33}
34
35impl TimedSignal {
36    /// Return a new instance.
37    pub fn new() -> Self {
38        Self::default()
39    }
40
41    /// Update internals and return state.
42    /// When an action is scheduled and tick reaches the specific value for that
43    /// action, the state is updated accordingly.
44    pub fn update(&mut self, tick: u64) -> bool {
45        match self.tick_action {
46            TickAction::Set(trigger_tick, state) => {
47                if tick >= trigger_tick {
48                    self.state = state;
49                    self.tick_action = TickAction::None;
50                }
51            }
52            TickAction::SetFor(duration_ticks, state) => {
53                self.state = state;
54                self.tick_action = TickAction::Set(tick + duration_ticks, !state);
55                return self.update(tick);
56            }
57            TickAction::Blink(blink_period) => {
58                self.state = (tick as u32 % blink_period) < (blink_period >> 1)
59            }
60            _ => {}
61        }
62
63        self.state()
64    }
65
66    /// Return current state.
67    pub fn state(&self) -> bool {
68        self.state ^ self.inverted
69    }
70
71    /// Set inverted state on/off.
72    pub fn set_inverted(&mut self, inverted: bool) {
73        self.inverted = inverted;
74    }
75
76    /// Return if state is inverted.
77    pub fn is_inverted(&self) -> bool {
78        self.inverted
79    }
80
81    /// Set state according to a boolean value.
82    pub fn set(&mut self, state: bool) {
83        self.state = state;
84        self.tick_action = TickAction::None;
85    }
86
87    /// Set on state.
88    pub fn on(&mut self) {
89        self.set(true);
90    }
91
92    /// Set off state.
93    pub fn off(&mut self) {
94        self.set(false);
95    }
96
97    /// Toggle state.
98    pub fn toggle(&mut self) {
99        self.set(!self.state);
100    }
101
102    /// Toggle state at a predefined rate with a 50% ratio.
103    /// `period` is the number of ticks for one period. E.g. if set to 4, the state will be
104    /// on for 2 ticks and off for another 2 ticks.
105    pub fn blink(&mut self, period: u32) {
106        self.tick_action = TickAction::Blink(period);
107    }
108
109    /// Set a state when a tick is reached.
110    pub fn set_at(&mut self, trigger_tick: u64, state: bool) {
111        self.tick_action = TickAction::Set(trigger_tick, state);
112    }
113
114    /// Set a state until a tick is reached, then return to previous state.
115    pub fn set_until(&mut self, trigger_tick: u64, state: bool) {
116        self.set(state);
117        self.tick_action = TickAction::Set(trigger_tick, !state);
118    }
119
120    /// Set a state for a number of ticks, then invert it. Single trigger.
121    pub fn set_for(&mut self, duration_ticks: u64, state: bool) {
122        if self.tick_action == TickAction::None {
123            self.tick_action = TickAction::SetFor(duration_ticks, state);
124        }
125    }
126
127    /// Set a state for a number of ticks, then invert it. Retrigger.
128    pub fn set_for_retrigger(&mut self, duration_ticks: u64, state: bool) {
129        self.tick_action = TickAction::SetFor(duration_ticks, state);
130    }
131
132    /// Set on state when a tick is reached.
133    pub fn on_at(&mut self, trigger_tick: u64) {
134        self.set_at(trigger_tick, true);
135    }
136
137    /// Set on state until a tick is reached, then set it off.
138    pub fn on_until(&mut self, trigger_tick: u64) {
139        self.set_until(trigger_tick, true);
140    }
141
142    /// Set on state for a number of ticks, then set it off.
143    pub fn on_for(&mut self, duration_ticks: u64) {
144        self.set_for(duration_ticks, true);
145    }
146
147    /// Set off state when a tick is reached.
148    pub fn off_at(&mut self, trigger_tick: u64) {
149        self.set_at(trigger_tick, false);
150    }
151
152    /// Set off state until a tick is reached, then set it on.
153    pub fn off_until(&mut self, trigger_tick: u64) {
154        self.set_until(trigger_tick, false);
155    }
156
157    /// Set off state for a number of ticks, then set it on.
158    pub fn off_for(&mut self, duration_ticks: u64) {
159        self.set_for(duration_ticks, false);
160    }
161
162    /// Toggle state when a tick is reached.
163    pub fn toggle_at(&mut self, trigger_tick: u64) {
164        if self.tick_action == TickAction::None {
165            self.tick_action = TickAction::Set(trigger_tick, !self.state);
166        }
167    }
168
169    /// Toggle state until a tick is reached, then return to previous state.
170    pub fn toggle_until(&mut self, trigger_tick: u64) {
171        if self.tick_action == TickAction::None {
172            self.toggle();
173            self.tick_action = TickAction::Set(trigger_tick, !self.state);
174        }
175    }
176
177    /// Toggle state for a number of ticks, then return to previous state. Single trigger.
178    pub fn toggle_for(&mut self, duration_ticks: u64) {
179        if self.tick_action == TickAction::None {
180            self.tick_action = TickAction::SetFor(duration_ticks, !self.state);
181        }
182    }
183
184    /// Toggle state for a number of ticks, then return to previous state. Retrigger.
185    pub fn toggle_for_retrigger(&mut self, duration_ticks: u64) {
186        match self.tick_action {
187            TickAction::Set(_, state) => {
188                self.tick_action = TickAction::SetFor(duration_ticks, !state);
189            }
190            _ => {
191                self.tick_action = TickAction::SetFor(duration_ticks, !self.state);
192            }
193        }
194    }
195}
196
197#[cfg(test)]
198mod tests;