autocore-std 3.3.30

Standard library for AutoCore control programs - shared memory, IPC, and logging utilities
Documentation
/// Rising Edge Trigger (R_TRIG)
///
/// Detects a rising edge (false → true transition) on the input signal.
/// The output `q` is `true` for exactly one cycle when the input `clk`
/// transitions from `false` to `true`.
///
/// This is equivalent to the IEC 61131-3 R_TRIG function block.
///
/// # Example
///
/// ```
/// use autocore_std::fb::RTrig;
///
/// let mut trigger = RTrig::new();
///
/// // No edge yet
/// assert_eq!(trigger.call(false), false);
///
/// // Rising edge detected!
/// assert_eq!(trigger.call(true), true);
///
/// // Signal still high, but edge already passed
/// assert_eq!(trigger.call(true), false);
/// assert_eq!(trigger.call(true), false);
///
/// // Signal goes low
/// assert_eq!(trigger.call(false), false);
///
/// // Another rising edge
/// assert_eq!(trigger.call(true), true);
/// ```
///
/// # Timing Diagram
///
/// ```text
/// clk: _____|‾‾‾‾‾‾‾‾‾|_____|‾‾‾‾‾
///   q: _____|‾|_____________|‾|____
/// ```
///
/// # Use Cases
///
/// - Detecting button presses (trigger on press, not hold)
/// - Counting events (increment counter on each rising edge)
/// - State machine transitions
#[derive(Debug, Clone)]
pub struct RTrig {
    /// Current input value
    pub clk: bool,
    /// Output: true for one cycle on rising edge
    pub q: bool,
    /// Internal memory of previous input state
    m: bool,
}

impl RTrig {
    /// Creates a new rising edge trigger with all values initialized to `false`.
    ///
    /// # Example
    ///
    /// ```
    /// use autocore_std::fb::RTrig;
    ///
    /// let trigger = RTrig::new();
    /// assert_eq!(trigger.q, false);
    /// ```
    pub fn new() -> Self {
        Self {
            clk: false,
            q: false,
            m: false,
        }
    }

    /// Executes the rising edge detection logic.
    ///
    /// Call this method once per control cycle with the current input value.
    /// Returns `true` for exactly one cycle when a rising edge is detected.
    ///
    /// # Arguments
    ///
    /// * `clk` - The current state of the input signal
    ///
    /// # Returns
    ///
    /// `true` if a rising edge (false → true transition) was detected, `false` otherwise.
    ///
    /// # Example
    ///
    /// ```
    /// use autocore_std::fb::RTrig;
    ///
    /// let mut trigger = RTrig::new();
    ///
    /// let button_pressed = true;
    /// if trigger.call(button_pressed) {
    ///     println!("Button was just pressed!");
    /// }
    /// ```
    pub fn call(&mut self, clk: bool) -> bool {
        self.clk = clk;
        self.q = self.clk && !self.m;
        self.m = self.clk;
        self.q
    }
}

impl Default for RTrig {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_rtrig_rising_edge() {
        let mut trigger = RTrig::new();

        // No edge initially
        assert_eq!(trigger.call(false), false);

        // Rising edge
        assert_eq!(trigger.call(true), true);

        // No edge while high
        assert_eq!(trigger.call(true), false);
        assert_eq!(trigger.call(true), false);

        // No edge on falling
        assert_eq!(trigger.call(false), false);

        // Rising edge again
        assert_eq!(trigger.call(true), true);
    }
}