bacnet_objects/analog/
mod.rs1use alloc::borrow::Cow;
6use bacnet_types::enums::{
7 EngineeringUnits, ErrorClass, ErrorCode, EventState, ObjectType, PropertyIdentifier,
8 Reliability,
9};
10use bacnet_types::error::Error;
11use bacnet_types::primitives::{BACnetTimeStamp, ObjectIdentifier, PropertyValue, StatusFlags};
12
13use crate::common::{self, read_common_properties};
14use crate::event::{OutOfRangeDetector, history::EventHistory};
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) -> Reliability {
31 match self {
32 Self::UnderRange => Reliability::UNDER_RANGE,
33 Self::OverRange => Reliability::OVER_RANGE,
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 clear_ownership(&mut self) {
65 self.owned_fault = None;
66 }
67
68 fn evaluate(
69 &mut self,
70 monitored_value: f32,
71 reliability: &mut Reliability,
72 ) -> Result<ReliabilityEvaluation, Error> {
73 let Some(limits) = self.limits else {
74 return Ok(ReliabilityEvaluation::Unchanged);
75 };
76 if !monitored_value.is_finite() {
77 return Err(common::value_out_of_range_error());
78 }
79 let observed_fault = if monitored_value < limits.low {
80 Some(OwnedRangeFault::UnderRange)
81 } else if monitored_value > limits.high {
82 Some(OwnedRangeFault::OverRange)
83 } else {
84 None
85 };
86
87 let (new_reliability, new_owner) = if self.owned_fault.is_some() {
88 (
89 observed_fault
90 .map(OwnedRangeFault::reliability)
91 .unwrap_or(Reliability::NO_FAULT_DETECTED),
92 observed_fault,
93 )
94 } else if *reliability == Reliability::NO_FAULT_DETECTED {
95 let Some(fault) = observed_fault else {
96 return Ok(ReliabilityEvaluation::Unchanged);
97 };
98 (fault.reliability(), Some(fault))
99 } else {
100 return Ok(ReliabilityEvaluation::Unchanged);
101 };
102
103 if new_reliability == *reliability {
104 return Ok(ReliabilityEvaluation::Unchanged);
105 }
106 let old_reliability = *reliability;
107 *reliability = new_reliability;
108 self.owned_fault = new_owner;
109 Ok(ReliabilityEvaluation::Changed {
110 old_reliability,
111 new_reliability,
112 })
113 }
114}
115
116const CREATION_ONLY: &[PropertyIdentifier] = &[PropertyIdentifier::UNITS];
119
120fn initialize_units(
124 units: &mut EngineeringUnits,
125 property: PropertyIdentifier,
126 value: PropertyValue,
127) -> Result<(), Error> {
128 if property != PropertyIdentifier::UNITS {
129 return Err(common::write_access_denied_error());
130 }
131 let PropertyValue::Enumerated(raw) = value else {
132 return Err(common::invalid_data_type_error());
133 };
134 if raw > 65_535 {
135 return Err(common::value_out_of_range_error());
136 }
137 *units = EngineeringUnits::from_raw(raw);
138 Ok(())
139}
140
141mod input;
142mod output;
143mod value;
144pub use input::*;
145pub use output::*;
146pub use value::*;
147
148#[cfg(test)]
153mod tests;