use crate::core::signal::direction::Direction;
use crate::core::signal::kind::{SignalKind, ThresholdSub};
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ThresholdKind {
Above,
Below,
InRange,
OutOfRange,
}
#[derive(Debug, Clone)]
pub struct Threshold {
kind: ThresholdKind,
upper: f64,
lower: f64,
last_state: Option<bool>,
}
impl Threshold {
pub fn new(kind: ThresholdKind, upper: f64, lower: f64) -> Self {
Self {
kind,
upper,
lower,
last_state: None,
}
}
pub fn single(kind: ThresholdKind, level: f64) -> Self {
Self::new(kind, level, level)
}
pub fn detect_from_values(&mut self, value: f64) -> Option<(SignalKind, Direction)> {
let current_state = match self.kind {
ThresholdKind::Above => value > self.upper,
ThresholdKind::Below => value < self.lower,
ThresholdKind::InRange => value >= self.lower && value <= self.upper,
ThresholdKind::OutOfRange => value < self.lower || value > self.upper,
};
let prev = self.last_state;
self.last_state = Some(current_state);
match prev {
None => None,
Some(was) if !was && current_state => {
let sub = match self.kind {
ThresholdKind::Above | ThresholdKind::InRange => ThresholdSub::Enter,
ThresholdKind::Below | ThresholdKind::OutOfRange => ThresholdSub::Exit,
};
let dir = if value >= self.lower {
Direction::Up
} else {
Direction::Down
};
Some((SignalKind::Threshold(sub), dir))
}
Some(was) if was && !current_state => {
let sub = match self.kind {
ThresholdKind::Above | ThresholdKind::InRange => ThresholdSub::Exit,
ThresholdKind::Below | ThresholdKind::OutOfRange => ThresholdSub::Enter,
};
let dir = if value < self.lower {
Direction::Down
} else {
Direction::Up
};
Some((SignalKind::Threshold(sub), dir))
}
_ => None,
}
}
pub fn reset(&mut self) {
self.last_state = None;
}
}