Skip to main content

autocore_std/fb/
f_trig.rs

1/// Falling Edge Trigger (F_TRIG)
2///
3/// Detects a falling edge (true → false transition) on the input signal.
4/// The output `q` is `true` for exactly one cycle when the input `clk`
5/// transitions from `true` to `false`.
6///
7/// This is equivalent to the IEC 61131-3 F_TRIG function block.
8///
9/// # Example
10///
11/// ```
12/// use autocore_std::fb::FTrig;
13///
14/// let mut trigger = FTrig::new();
15///
16/// // Signal starts low
17/// assert_eq!(trigger.call(false), false);
18///
19/// // Signal goes high
20/// assert_eq!(trigger.call(true), false);
21///
22/// // Falling edge detected!
23/// assert_eq!(trigger.call(false), true);
24///
25/// // Signal still low, edge already passed
26/// assert_eq!(trigger.call(false), false);
27/// ```
28///
29/// # Timing Diagram
30///
31/// ```text
32/// clk: _____|‾‾‾‾‾‾‾‾‾|_____|‾‾‾‾‾
33///   q: _______________|‾|________
34/// ```
35///
36/// # Use Cases
37///
38/// - Detecting button releases
39/// - Detecting signal loss
40/// - Triggering actions when a condition ends
41#[derive(Debug, Clone)]
42pub struct FTrig {
43    /// Current input value
44    pub clk: bool,
45    /// Output: true for one cycle on falling edge
46    pub q: bool,
47    /// Internal memory of previous input state
48    m: bool,
49}
50
51impl FTrig {
52    /// Creates a new falling edge trigger with all values initialized to `false`.
53    ///
54    /// # Example
55    ///
56    /// ```
57    /// use autocore_std::fb::FTrig;
58    ///
59    /// let trigger = FTrig::new();
60    /// assert_eq!(trigger.q, false);
61    /// ```
62    pub fn new() -> Self {
63        Self {
64            clk: false,
65            q: false,
66            m: false,
67        }
68    }
69
70    /// Executes the falling edge detection logic.
71    ///
72    /// Call this method once per control cycle with the current input value.
73    /// Returns `true` for exactly one cycle when a falling edge is detected.
74    ///
75    /// # Arguments
76    ///
77    /// * `clk` - The current state of the input signal
78    ///
79    /// # Returns
80    ///
81    /// `true` if a falling edge (true → false transition) was detected, `false` otherwise.
82    ///
83    /// # Example
84    ///
85    /// ```
86    /// use autocore_std::fb::FTrig;
87    ///
88    /// let mut trigger = FTrig::new();
89    ///
90    /// // Simulate button release
91    /// trigger.call(true);  // Button held
92    /// if trigger.call(false) {  // Button released
93    ///     println!("Button was just released!");
94    /// }
95    /// ```
96    pub fn call(&mut self, clk: bool) -> bool {
97        self.clk = clk;
98        self.q = !self.clk && self.m;
99        self.m = self.clk;
100        self.q
101    }
102}
103
104impl Default for FTrig {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_ftrig_falling_edge() {
116        let mut trigger = FTrig::new();
117
118        // No edge initially
119        assert_eq!(trigger.call(false), false);
120
121        // No edge on rising
122        assert_eq!(trigger.call(true), false);
123
124        // Falling edge
125        assert_eq!(trigger.call(false), true);
126
127        // No edge while low
128        assert_eq!(trigger.call(false), false);
129
130        // Rising, then falling edge
131        assert_eq!(trigger.call(true), false);
132        assert_eq!(trigger.call(false), true);
133    }
134}