on_off_sequence_output/
lib.rs

1//! Output of a sequence of on/off states
2//!
3//! * the state sequence can be modified
4//! * the sequence can be repeated
5//! * An `update()` should be called periodically progress the output
6//!   in time.
7//!
8//! # Implementation
9//!
10//! * The OutputLED Structure aggregates a GPIO, (bound at init)
11//! * Output Pattern can be changed, while the GPIO binding is fixed
12//! * A trait (for update) is used to cope with propagate GPIO errors
13//! * A prelude simplifies getting the trait in scope
14//!
15//! # Example
16//!
17//! For examples check the examples directory
18//! directory in the repository.
19//!
20//! ```rust,ignore
21//! use on_off_sequence_output::prelude::*;
22//!
23//! // This is up to the implementation details of the embedded_hal you are using.
24//! let led_pin: OutputPin = hal_function_which_returns_output_pin();
25//!
26//! const UPDATE_SCALE: u16 = 500;
27//! let mut led = OnOffSequenceOutput::new(led_pin, UPDATE_SCALE);
28//!
29//! let output_states = 0b10011101;
30//! let number_of_output_states = 8;
31//! led.set(output_states, number_of_output_states, Repeat::Never)
32//! loop {
33//!    if led.update().unwrap() { break; };
34//!    wait(1.ms());
35//! }
36//!
37//! led.set(0b010, 3, Repeat::Times(2))
38//! loop {
39//!    if led.update().unwrap() { break; };
40//!    wait(1.ms());
41//! }
42//!
43//! led.set(0b10, 2, Repeat::Forever)
44//! loop {
45//!    led.update().unwrap();
46//!    wait(1.ms());
47//! }
48
49//! ```
50
51#![no_std]
52
53pub mod prelude;
54
55pub mod morse;
56
57use embedded_hal::digital::v2::OutputPin;
58use morse::{str_to_morse, MorseError};
59// use bitset_core::BitSet;
60
61/// How often shall the output repeated
62#[derive(Clone, Copy, Debug, PartialEq)]
63pub enum Repeat {
64    Never,
65    Times(u16),
66    Forever,
67}
68
69/// OutputUpdate Trait which provides an `update()` method
70pub trait OutputUpdate {
71    type Error;
72
73    /// Updates the output logic and potentially switches the LED state
74    ///
75    /// # Returns
76    ///
77    /// * Error - if the hardware GPIO switch to on/off failed
78    /// * true - if no further update repetitions are necessary to complete the
79    ///   the output
80    /// * false - otherwise
81    ///
82    /// # Notes
83    ///
84    /// * Needs to be called periodically.
85    /// * Side Effect: calls the aggregated GPIO pin to switch on/off
86    fn update(&mut self) -> Result<bool, Self::Error>;
87}
88
89/// Output of blinking patterns on an LED
90pub struct OnOffSequenceOutput<T: OutputPin> {
91    /// The wrapped output pin.
92    pub pin: T,
93
94    /// The update scaler: the clock rate at wich the output state changes
95    /// is equivalent the frequency of the update calls times *update_scale*
96    update_scale: u16,
97
98    /// The repeat configuration
99    repeat: Repeat,
100
101    /// The output states are represented by the bits of an unsigned 128-bit integer
102    output_states: u128,
103
104    /// How many bits are considered (min 1, max: 128)
105    number_of_output_states: u16,
106
107    /// Internal state: Manage scaling
108    scale_index: u16,
109
110    /// internal state: Manage next output state
111    state_index: u16,
112
113    /// Internal state: Run output indicator
114    ///
115    /// # Values
116    ///
117    /// * true - either a run is not completed or there are more repetitions to do
118    /// * false - run is completed (intermediate) and no more repetitions are
119    ///   needed.
120    run_output: bool,
121}
122
123impl<T: OutputPin> OnOffSequenceOutput<T> {
124    /// Initializes a new led output
125    ///
126    /// # Arguments
127    ///
128    /// * `pin` - An as output initialized GPIO pin
129    /// * `update_scale` - Scale factor:
130    ///      state change frequency = update frequency * update_scale
131    ///
132    /// # Notes
133    ///
134    /// * Default is symmetrically blinking forever
135    pub fn new(pin: T, update_scale: u16) -> Self {
136        Self {
137            pin,
138            update_scale,
139            output_states: 0b_10_u128,
140            number_of_output_states: 2,
141            repeat: Repeat::Forever,
142            scale_index: 0u16,
143            state_index: 0u16,
144            run_output: true,
145        }
146    }
147
148    fn reinitialize_internal_state(&mut self) {
149        self.scale_index = 0u16;
150        self.state_index = 0u16;
151        self.run_output = true;
152    }
153
154    /// Set a new output
155    ///
156    /// # Arguments
157    ///
158    /// * `output_states` - bits of a unsigned number: 1 equals on; 0 equals off
159    ///   The bits are processes from lsb to msb.
160    /// * `number_of_output_states` - how many bits of the fixed number are
161    ///   considered to for the output state sequence counted from lsb
162    /// * `repeat` - How often is the pattern repeated
163    ///
164    pub fn set(&mut self, output_states: u128, number_of_output_states: u16, repeat: Repeat) {
165        if number_of_output_states > 127 {
166            panic!("Must be less than 128 output states");
167        };
168        if number_of_output_states == 0 {
169            panic!("Zero output states do not make sense");
170        };
171        self.output_states = output_states;
172        self.number_of_output_states = number_of_output_states;
173        self.repeat = repeat;
174        self.reinitialize_internal_state();
175    }
176
177    /// Set a new morse code as output
178    ///
179    /// # Arguments
180    ///
181    /// * `morse_text` - Short text to be output as morse code sequence
182    /// * `repeat` - How often the morse text is repeated
183    ///
184    /// # Returns
185    ///
186    /// A result structure
187    ///
188    /// * with empty value if Ok()
189    /// * or Err(MorseError)
190    pub fn set_morse(&mut self, morse_text: &str, repeat: Repeat) -> Result<(), MorseError> {
191        let t = str_to_morse(morse_text)?;
192        self.output_states = t.0;
193        self.number_of_output_states = t.1;
194        self.reinitialize_internal_state();
195        self.repeat = repeat;
196        Ok(())
197    }
198}
199
200/// check if a certain position is set
201fn state_at_position(states: u128, position: u16) -> bool {
202    let mask: u128 = 1 << position;
203    if (states & mask) == 0 {
204        return false;
205    }
206    true
207}
208
209impl<T: OutputPin> OutputUpdate for OnOffSequenceOutput<T> {
210    type Error = T::Error;
211
212    /// Updates the output logic and potentially switches the LED state
213    fn update(&mut self) -> Result<bool, Self::Error> {
214        // handle the update scale
215        self.scale_index += 1;
216        if self.update_scale > self.scale_index {
217            return Ok(!self.run_output);
218        }
219        self.scale_index = 0;
220
221        // handle the output sequence
222        if self.run_output {
223            // if we get here, always some output has to happen
224            if state_at_position(self.output_states, self.state_index) {
225                self.pin.set_high()?;
226            } else {
227                self.pin.set_low()?;
228            }
229            self.state_index += 1;
230            if self.state_index >= self.number_of_output_states {
231                // all states are "printed"
232                self.run_output = false;
233                self.state_index = 0;
234            } else {
235            }
236        }
237
238        // handle the repetitions
239        if !self.run_output {
240            self.repeat = match self.repeat {
241                Repeat::Never => Repeat::Never,
242                Repeat::Forever => Repeat::Forever,
243                Repeat::Times(n) => {
244                    if n > 0 {
245                        Repeat::Times(n - 1)
246                    } else {
247                        Repeat::Never
248                    }
249                }
250            };
251            self.run_output = match self.repeat {
252                Repeat::Never => false,
253                Repeat::Forever => true,
254                Repeat::Times(_) => true,
255            };
256        }
257
258        Ok(!self.run_output)
259    }
260}
261
262/// Determine at position of the most left one in the bitfield represented as u128
263///
264/// # Arguments
265///
266/// * `bitfield` -  The bitfield to find the most left bit that is set to one
267///
268/// # Returns
269///
270/// *
271pub fn position_of_highest_one(bitfield: u128) -> u16 {
272    const MSB_ONE: u128 = 1 << 127;
273
274    let mut position = 127_u16;
275    let mut bitfield = bitfield;
276    while (bitfield & MSB_ONE) == 0 && position > 0 {
277        bitfield = bitfield << 1;
278        position -= 1;
279    }
280    position
281}
282
283pub mod macros {
284    /// Simplified setting of the output without repetitions
285    ///
286    /// The number of the output states is automatically computed
287    /// It requires that the last output state equals to one
288    ///
289    /// # Arguments
290    ///
291    /// * `Instance of OnOffSequenceOutput`
292    /// * `bitfield (u128)` - MSB of the Output sequence must be one
293    ///
294    /// # Examples
295    ///
296    /// ```rust,ignore
297    /// set_output_once!(ledout, 0b1100);
298    /// // ... is equivalent to ...
299    /// // ledout.set(0b1100, 4, Repeat::Never);
300    /// ```
301    #[macro_export]
302    macro_rules! set_output_once {
303        ($a:expr, $b:expr) => {
304            $a.set($b, position_of_highest_one($b), Repeat::Never)
305        };
306    }
307
308    /// Simplified setting of the output with infinite repetitions
309    ///
310    /// The number of the output states is automatically computed
311    /// It requires that the last output state equals to one
312    ///
313    /// # Arguments
314    ///
315    /// * `Instance of OnOffSequenceOutput`
316    /// * `bitfield (u128)` - MSB of the Output sequence must be one
317    ///
318    /// # Examples
319    /// ```rust,ignore
320    /// set_output_forever!(ledout, 0b1000);
321    /// // ... is equivalent to ...
322    /// // ledout.set(0b1000, 4, Repeat::Forever);
323    /// ```
324
325    #[macro_export]
326    macro_rules! set_output_forever {
327        ($a:expr, $b:expr) => {
328            $a.set($b, position_of_highest_one($b), Repeat::Forever)
329        };
330    }
331}
332
333#[cfg(test)]
334mod tests;