bacnet_objects/analog/
mod.rs1use bacnet_types::enums::{
6 ErrorClass, ErrorCode, EventState, ObjectType, PropertyIdentifier, Reliability,
7};
8use bacnet_types::error::Error;
9use bacnet_types::primitives::{BACnetTimeStamp, ObjectIdentifier, PropertyValue, StatusFlags};
10use std::borrow::Cow;
11
12use crate::common::{self, read_common_properties};
13use crate::event::{history::EventHistory, OutOfRangeDetector};
14use crate::rollback::impl_intrinsic_write_rollback;
15use crate::traits::{BACnetObject, ReliabilityEvaluation};
16
17#[derive(Clone, Copy)]
18struct FaultOutOfRangeLimits {
19 low: f32,
20 high: f32,
21}
22
23#[derive(Clone, Copy, PartialEq, Eq)]
24pub(crate) enum OwnedRangeFault {
25 UnderRange,
26 OverRange,
27}
28
29impl OwnedRangeFault {
30 fn reliability(self) -> u32 {
31 match self {
32 Self::UnderRange => Reliability::UNDER_RANGE.to_raw(),
33 Self::OverRange => Reliability::OVER_RANGE.to_raw(),
34 }
35 }
36}
37
38#[derive(Default)]
39struct FaultOutOfRangeState {
40 limits: Option<FaultOutOfRangeLimits>,
43 owned_fault: Option<OwnedRangeFault>,
44}
45
46impl FaultOutOfRangeState {
47 fn configure(&mut self, low: f32, high: f32) -> Result<(), Error> {
48 if !low.is_finite() || !high.is_finite() || low > high {
49 return Err(common::value_out_of_range_error());
50 }
51 self.limits = Some(FaultOutOfRangeLimits { low, high });
52 Ok(())
53 }
54
55 fn read_limit(&self, property: PropertyIdentifier) -> Option<PropertyValue> {
56 let limits = self.limits?;
57 match property {
58 PropertyIdentifier::FAULT_LOW_LIMIT => Some(PropertyValue::Real(limits.low)),
59 PropertyIdentifier::FAULT_HIGH_LIMIT => Some(PropertyValue::Real(limits.high)),
60 _ => None,
61 }
62 }
63
64 fn property_list(
65 &self,
66 base: &'static [PropertyIdentifier],
67 ) -> Cow<'static, [PropertyIdentifier]> {
68 if self.limits.is_none() {
69 return Cow::Borrowed(base);
70 }
71 let mut properties = Vec::with_capacity(base.len() + 2);
72 properties.extend_from_slice(base);
73 properties.extend([
74 PropertyIdentifier::FAULT_HIGH_LIMIT,
75 PropertyIdentifier::FAULT_LOW_LIMIT,
76 ]);
77 Cow::Owned(properties)
78 }
79
80 fn clear_ownership(&mut self) {
81 self.owned_fault = None;
82 }
83
84 fn evaluate(
85 &mut self,
86 monitored_value: f32,
87 reliability: &mut u32,
88 ) -> Result<ReliabilityEvaluation, Error> {
89 let Some(limits) = self.limits else {
90 return Ok(ReliabilityEvaluation::Unchanged);
91 };
92 if !monitored_value.is_finite() {
93 return Err(common::value_out_of_range_error());
94 }
95 let observed_fault = if monitored_value < limits.low {
96 Some(OwnedRangeFault::UnderRange)
97 } else if monitored_value > limits.high {
98 Some(OwnedRangeFault::OverRange)
99 } else {
100 None
101 };
102
103 let (new_reliability, new_owner) = if self.owned_fault.is_some() {
104 (
105 observed_fault
106 .map(OwnedRangeFault::reliability)
107 .unwrap_or_else(|| Reliability::NO_FAULT_DETECTED.to_raw()),
108 observed_fault,
109 )
110 } else if *reliability == Reliability::NO_FAULT_DETECTED.to_raw() {
111 let Some(fault) = observed_fault else {
112 return Ok(ReliabilityEvaluation::Unchanged);
113 };
114 (fault.reliability(), Some(fault))
115 } else {
116 return Ok(ReliabilityEvaluation::Unchanged);
117 };
118
119 if new_reliability == *reliability {
120 return Ok(ReliabilityEvaluation::Unchanged);
121 }
122 let old_reliability = *reliability;
123 *reliability = new_reliability;
124 self.owned_fault = new_owner;
125 Ok(ReliabilityEvaluation::Changed {
126 old_reliability,
127 new_reliability,
128 })
129 }
130}
131
132mod input;
133mod output;
134mod value;
135pub use input::*;
136pub use output::*;
137pub use value::*;
138
139#[cfg(test)]
144mod tests;