autocore_std/fb/bit_reset_on_delay.rs
1use std::time::Duration;
2use super::ton::Ton;
3
4/// Resets a boolean value after it has been true for a specified duration.
5///
6/// This function block monitors a boolean value and, once it has been
7/// continuously `true` for the preset time `pt`, resets it to `false`.
8/// It uses a [`Ton`] timer internally.
9///
10/// IEC 61131-3 equivalent:
11/// ```text
12/// tonValue(IN := Value^, PT := PT);
13/// IF tonValue.Q THEN
14/// Value^ := FALSE;
15/// END_IF
16/// ```
17///
18/// # Example
19///
20/// ```
21/// use autocore_std::fb::BitResetOnDelay;
22/// use std::time::Duration;
23///
24/// let mut reset_delay = BitResetOnDelay::new();
25/// let mut flag = true;
26///
27/// // Flag is true, timer starts counting
28/// reset_delay.call(&mut flag, Duration::from_millis(50));
29/// assert_eq!(flag, true); // Not yet reset
30///
31/// // After delay elapses, flag is reset to false
32/// std::thread::sleep(Duration::from_millis(60));
33/// reset_delay.call(&mut flag, Duration::from_millis(50));
34/// assert_eq!(flag, false);
35/// ```
36///
37/// # Use Cases
38///
39/// - Auto-clearing acknowledgment flags
40/// - Resetting one-shot signals after a hold time
41/// - Automatically turning off indicators after a display period
42#[derive(Debug, Clone)]
43pub struct BitResetOnDelay {
44 ton: Ton,
45}
46
47impl BitResetOnDelay {
48 /// Creates a new `BitResetOnDelay` with the internal timer in its default state.
49 ///
50 /// # Example
51 ///
52 /// ```
53 /// use autocore_std::fb::BitResetOnDelay;
54 ///
55 /// let reset_delay = BitResetOnDelay::new();
56 /// ```
57 pub fn new() -> Self {
58 Self { ton: Ton::new() }
59 }
60
61 /// Call cyclically. Resets `value` to `false` after it has been
62 /// `true` for the duration `pt`.
63 ///
64 /// When `value` is `false`, the internal timer resets. When `value`
65 /// is `true`, the timer counts up. Once the timer reaches `pt`,
66 /// `value` is set to `false`.
67 ///
68 /// # Arguments
69 ///
70 /// * `value` - Mutable reference to the boolean to monitor and reset
71 /// * `pt` - Duration that `value` must be `true` before it is reset
72 ///
73 /// # Example
74 ///
75 /// ```
76 /// use autocore_std::fb::BitResetOnDelay;
77 /// use std::time::Duration;
78 ///
79 /// let mut reset_delay = BitResetOnDelay::new();
80 /// let mut alarm_ack = false;
81 ///
82 /// // No effect when value is false
83 /// reset_delay.call(&mut alarm_ack, Duration::from_millis(100));
84 /// assert_eq!(alarm_ack, false);
85 ///
86 /// // Set the flag
87 /// alarm_ack = true;
88 /// reset_delay.call(&mut alarm_ack, Duration::from_millis(100));
89 /// assert_eq!(alarm_ack, true); // Still true, timer just started
90 /// ```
91 pub fn call(&mut self, value: &mut bool, pt: Duration) {
92 self.ton.call(*value, pt);
93 if self.ton.q {
94 *value = false;
95 }
96 }
97}
98
99impl Default for BitResetOnDelay {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_resets_after_delay() {
111 let mut fb = BitResetOnDelay::new();
112 let mut flag = true;
113 let pt = Duration::from_millis(50);
114
115 // First call: timer starts, flag stays true
116 fb.call(&mut flag, pt);
117 assert_eq!(flag, true);
118
119 // Wait for timer to elapse
120 std::thread::sleep(Duration::from_millis(60));
121
122 // Timer elapsed: flag should be reset to false
123 fb.call(&mut flag, pt);
124 assert_eq!(flag, false);
125 }
126
127 #[test]
128 fn test_no_effect_when_false() {
129 let mut fb = BitResetOnDelay::new();
130 let mut flag = false;
131 let pt = Duration::from_millis(50);
132
133 fb.call(&mut flag, pt);
134 assert_eq!(flag, false);
135
136 std::thread::sleep(Duration::from_millis(60));
137 fb.call(&mut flag, pt);
138 assert_eq!(flag, false);
139 }
140
141 #[test]
142 fn test_timer_resets_when_value_goes_false() {
143 let mut fb = BitResetOnDelay::new();
144 let mut flag = true;
145 let pt = Duration::from_millis(100);
146
147 // Start timing
148 fb.call(&mut flag, pt);
149 assert_eq!(flag, true);
150
151 std::thread::sleep(Duration::from_millis(40));
152 fb.call(&mut flag, pt);
153 assert_eq!(flag, true);
154
155 // Value goes false before timer elapses
156 flag = false;
157 fb.call(&mut flag, pt);
158 assert_eq!(flag, false);
159
160 // Value goes true again — timer restarts
161 flag = true;
162 fb.call(&mut flag, pt);
163 assert_eq!(flag, true);
164
165 // Not enough time yet
166 std::thread::sleep(Duration::from_millis(40));
167 fb.call(&mut flag, pt);
168 assert_eq!(flag, true);
169
170 // Now enough time
171 std::thread::sleep(Duration::from_millis(70));
172 fb.call(&mut flag, pt);
173 assert_eq!(flag, false);
174 }
175
176 #[test]
177 fn test_default_trait() {
178 let fb = BitResetOnDelay::default();
179 assert!(!fb.ton.q);
180 }
181}