1use crate::{AlarmMetadata, ControlMetadata};
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
6pub enum AlarmSeverity {
7 NoAlarm = 0,
8 Minor = 1,
9 Major = 2,
10 Invalid = 3,
11 UndefinedAlarm = 4,
12}
13impl Default for AlarmSeverity {
14 fn default() -> Self {
15 AlarmSeverity::NoAlarm
16 }
17}
18
19impl From<i32> for AlarmSeverity {
20 fn from(value: i32) -> Self {
21 match value {
22 0 => AlarmSeverity::NoAlarm,
23 1 => AlarmSeverity::Minor,
24 2 => AlarmSeverity::Major,
25 3 => AlarmSeverity::Invalid,
26 4 => AlarmSeverity::UndefinedAlarm,
27 _ => AlarmSeverity::UndefinedAlarm,
28 }
29 }
30}
31
32#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
33pub enum AlarmStatus {
34 NoAlarm = 0,
35 DeviceStatus = 1,
36 DriverStatus = 2,
37 RecordStatus = 3,
38 DbStatus = 4,
39 ConfigStatus = 5,
40 UndefinedStatus = 6,
41 ClientStatus = 7,
42}
43
44impl Default for AlarmStatus {
45 fn default() -> Self {
46 AlarmStatus::NoAlarm
47 }
48}
49
50impl From<i32> for AlarmStatus {
51 fn from(value: i32) -> Self {
52 match value {
53 0 => AlarmStatus::NoAlarm,
54 1 => AlarmStatus::DeviceStatus,
55 2 => AlarmStatus::DriverStatus,
56 3 => AlarmStatus::RecordStatus,
57 4 => AlarmStatus::DbStatus,
58 5 => AlarmStatus::ConfigStatus,
59 6 => AlarmStatus::UndefinedStatus,
60 7 => AlarmStatus::ClientStatus,
61 _ => AlarmStatus::UndefinedStatus,
62 }
63 }
64}
65
66#[derive(Clone, Debug, Default)]
67pub struct AlarmConfig {
68 pub(crate) control: Option<ControlMetadata>,
69 pub(crate) alarm_metadata: Option<AlarmMetadata>,
70}
71
72#[derive(Clone, Debug)]
73pub struct AlarmResult {
74 pub(crate) allow: bool,
75 pub(crate) severity: AlarmSeverity,
76 pub(crate) status: AlarmStatus,
77 pub(crate) message: String,
78}
79
80pub fn compute_alarm_for_scalar(value: f64, config: &AlarmConfig) -> AlarmResult {
81 if let Some(control) = &config.control {
83 let hysteresis = config
84 .alarm_metadata
85 .as_ref()
86 .map_or(0.0, |m| m.hysteresis as f64);
87 if value < control.limit_low + hysteresis || value > control.limit_high - hysteresis {
88 return AlarmResult {
89 allow: false,
90 severity: AlarmSeverity::Invalid,
91 status: AlarmStatus::RecordStatus,
92 message: "OUT_OF_CONTROL_LIMITS".to_string(),
93 };
94 }
95 }
96
97 if let Some(value_alarm) = &config.alarm_metadata {
98 if value_alarm.active {
99 if value <= value_alarm.low_alarm_limit + value_alarm.hysteresis as f64 {
100 return AlarmResult {
101 allow: true,
102 severity: value_alarm.low_alarm_severity,
103 status: AlarmStatus::DeviceStatus,
104 message: "LOW_ALARM".to_string(),
105 };
106 }
107 if value <= value_alarm.low_warning_limit + value_alarm.hysteresis as f64 {
108 return AlarmResult {
109 allow: true,
110 severity: value_alarm.low_warning_severity,
111 status: AlarmStatus::DeviceStatus,
112 message: "LOW_WARNING".to_string(),
113 };
114 }
115 if value >= value_alarm.high_alarm_limit - value_alarm.hysteresis as f64 {
116 return AlarmResult {
117 allow: true,
118 severity: value_alarm.high_alarm_severity,
119 status: AlarmStatus::DeviceStatus,
120 message: "HIGH_ALARM".to_string(),
121 };
122 }
123 if value >= value_alarm.high_warning_limit - value_alarm.hysteresis as f64 {
124 return AlarmResult {
125 allow: true,
126 severity: value_alarm.high_warning_severity,
127 status: AlarmStatus::DeviceStatus,
128 message: "HIGH_WARNING".to_string(),
129 };
130 }
131 }
132 }
133
134 AlarmResult {
135 allow: true,
136 severity: AlarmSeverity::NoAlarm,
137 status: AlarmStatus::NoAlarm,
138 message: "OK".to_string(),
139 }
140}