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::traits::{BACnetObject, ReliabilityEvaluation};
15
16#[derive(Clone, Copy)]
17struct FaultOutOfRangeLimits {
18 low: f32,
19 high: f32,
20}
21
22#[derive(Clone, Copy, PartialEq, Eq)]
23pub(crate) enum OwnedRangeFault {
24 UnderRange,
25 OverRange,
26}
27
28impl OwnedRangeFault {
29 fn reliability(self) -> Reliability {
30 match self {
31 Self::UnderRange => Reliability::UNDER_RANGE,
32 Self::OverRange => Reliability::OVER_RANGE,
33 }
34 }
35}
36
37#[derive(Default)]
38struct FaultOutOfRangeState {
39 limits: Option<FaultOutOfRangeLimits>,
42 owned_fault: Option<OwnedRangeFault>,
43}
44
45impl FaultOutOfRangeState {
46 fn configure(&mut self, low: f32, high: f32) -> Result<(), Error> {
47 if !low.is_finite() || !high.is_finite() || low > high {
48 return Err(common::value_out_of_range_error());
49 }
50 self.limits = Some(FaultOutOfRangeLimits { low, high });
51 Ok(())
52 }
53
54 fn read_limit(&self, property: PropertyIdentifier) -> Option<PropertyValue> {
55 let limits = self.limits?;
56 match property {
57 PropertyIdentifier::FAULT_LOW_LIMIT => Some(PropertyValue::Real(limits.low)),
58 PropertyIdentifier::FAULT_HIGH_LIMIT => Some(PropertyValue::Real(limits.high)),
59 _ => None,
60 }
61 }
62
63 fn clear_ownership(&mut self) {
64 self.owned_fault = None;
65 }
66
67 fn evaluate(
68 &mut self,
69 monitored_value: f32,
70 reliability: &mut Reliability,
71 ) -> Result<ReliabilityEvaluation, Error> {
72 let Some(limits) = self.limits else {
73 return Ok(ReliabilityEvaluation::Unchanged);
74 };
75 if !monitored_value.is_finite() {
76 return Err(common::value_out_of_range_error());
77 }
78 let observed_fault = if monitored_value < limits.low {
79 Some(OwnedRangeFault::UnderRange)
80 } else if monitored_value > limits.high {
81 Some(OwnedRangeFault::OverRange)
82 } else {
83 None
84 };
85
86 let (new_reliability, new_owner) = if self.owned_fault.is_some() {
87 (
88 observed_fault
89 .map(OwnedRangeFault::reliability)
90 .unwrap_or(Reliability::NO_FAULT_DETECTED),
91 observed_fault,
92 )
93 } else if *reliability == Reliability::NO_FAULT_DETECTED {
94 let Some(fault) = observed_fault else {
95 return Ok(ReliabilityEvaluation::Unchanged);
96 };
97 (fault.reliability(), Some(fault))
98 } else {
99 return Ok(ReliabilityEvaluation::Unchanged);
100 };
101
102 if new_reliability == *reliability {
103 return Ok(ReliabilityEvaluation::Unchanged);
104 }
105 let old_reliability = *reliability;
106 *reliability = new_reliability;
107 self.owned_fault = new_owner;
108 Ok(ReliabilityEvaluation::Changed {
109 old_reliability,
110 new_reliability,
111 })
112 }
113}
114
115const CREATION_ONLY: &[PropertyIdentifier] = &[PropertyIdentifier::UNITS];
118
119fn initialize_units(
123 units: &mut u32,
124 property: PropertyIdentifier,
125 value: PropertyValue,
126) -> Result<(), Error> {
127 if property != PropertyIdentifier::UNITS {
128 return Err(common::write_access_denied_error());
129 }
130 let PropertyValue::Enumerated(raw) = value else {
131 return Err(common::invalid_data_type_error());
132 };
133 if raw > 65_535 {
134 return Err(common::value_out_of_range_error());
135 }
136 *units = raw;
137 Ok(())
138}
139
140mod input;
141mod output;
142mod value;
143pub use input::*;
144pub use output::*;
145pub use value::*;
146
147#[cfg(test)]
152mod tests;