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}