autocore-std 3.3.19

Standard library for AutoCore control programs - shared memory, IPC, and logging utilities
Documentation
/// Falling Edge Trigger (F_TRIG)
///
/// Detects a falling edge (true → false transition) on the input signal.
/// The output `q` is `true` for exactly one cycle when the input `clk`
/// transitions from `true` to `false`.
///
/// This is equivalent to the IEC 61131-3 F_TRIG function block.
///
/// # Example
///
/// ```
/// use autocore_std::fb::FTrig;
///
/// let mut trigger = FTrig::new();
///
/// // Signal starts low
/// assert_eq!(trigger.call(false), false);
///
/// // Signal goes high
/// assert_eq!(trigger.call(true), false);
///
/// // Falling edge detected!
/// assert_eq!(trigger.call(false), true);
///
/// // Signal still low, edge already passed
/// assert_eq!(trigger.call(false), false);
/// ```
///
/// # Timing Diagram
///
/// ```text
/// clk: _____|‾‾‾‾‾‾‾‾‾|_____|‾‾‾‾‾
///   q: _______________|‾|________
/// ```
///
/// # Use Cases
///
/// - Detecting button releases
/// - Detecting signal loss
/// - Triggering actions when a condition ends
#[derive(Debug, Clone)]
pub struct FTrig {
    /// Current input value
    pub clk: bool,
    /// Output: true for one cycle on falling edge
    pub q: bool,
    /// Internal memory of previous input state
    m: bool,
}

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

    /// Executes the falling edge detection logic.
    ///
    /// Call this method once per control cycle with the current input value.
    /// Returns `true` for exactly one cycle when a falling edge is detected.
    ///
    /// # Arguments
    ///
    /// * `clk` - The current state of the input signal
    ///
    /// # Returns
    ///
    /// `true` if a falling edge (true → false transition) was detected, `false` otherwise.
    ///
    /// # Example
    ///
    /// ```
    /// use autocore_std::fb::FTrig;
    ///
    /// let mut trigger = FTrig::new();
    ///
    /// // Simulate button release
    /// trigger.call(true);  // Button held
    /// if trigger.call(false) {  // Button released
    ///     println!("Button was just released!");
    /// }
    /// ```
    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 FTrig {
    fn default() -> Self {
        Self::new()
    }
}

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

    #[test]
    fn test_ftrig_falling_edge() {
        let mut trigger = FTrig::new();

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

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

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

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

        // Rising, then falling edge
        assert_eq!(trigger.call(true), false);
        assert_eq!(trigger.call(false), true);
    }
}