Skip to main content

autocore_std/fb/
r_trig.rs

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