1use super::*;
2
3pub struct BinaryValueObject {
12 oid: ObjectIdentifier,
13 name: String,
14 description: String,
15 present_value: u32, out_of_service: bool,
17 status_flags: StatusFlags,
18 priority_array: [Option<u32>; 16],
19 relinquish_default: u32,
20 reliability: u32,
22 reliability_before_out_of_service: Option<u32>,
23 reliability_inhibit: common::ReliabilityInhibitState,
24 active_text: String,
25 inactive_text: String,
26 event_detector: ChangeOfStateDetector,
28 event_detection_enable: bool,
31 pub(crate) event_history: EventHistory,
32 value_source: common::ValueSourceTracking,
34}
35
36impl BinaryValueObject {
37 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
39 let oid = ObjectIdentifier::new(ObjectType::BINARY_VALUE, instance)?;
40 Ok(Self {
41 oid,
42 name: name.into(),
43 description: String::new(),
44 present_value: 0, out_of_service: false,
46 status_flags: StatusFlags::empty(),
47 priority_array: [None; 16],
48 relinquish_default: 0,
49 reliability: 0,
50 reliability_before_out_of_service: None,
51 reliability_inhibit: common::ReliabilityInhibitState::default(),
52 active_text: "Active".into(),
53 inactive_text: "Inactive".into(),
54 event_detector: ChangeOfStateDetector {
55 alarm_values: vec![1],
56 ..Default::default()
57 },
58 event_detection_enable: true,
59 event_history: EventHistory::default(),
60 value_source: common::ValueSourceTracking::default(),
61 })
62 }
63
64 pub fn set_description(&mut self, desc: impl Into<String>) {
66 self.description = desc.into();
67 }
68
69 fn recalculate_present_value(&mut self) {
70 self.present_value =
71 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
72 }
73
74 pub fn set_relinquish_default(&mut self, value: u32) -> Result<(), Error> {
80 if value > 1 {
81 return Err(common::value_out_of_range_error());
82 }
83 self.relinquish_default = value;
84 self.recalculate_present_value();
85 Ok(())
86 }
87}
88
89impl BACnetObject for BinaryValueObject {
90 fn object_identifier(&self) -> ObjectIdentifier {
91 self.oid
92 }
93
94 fn object_name(&self) -> &str {
95 &self.name
96 }
97
98 fn supports_cov(&self) -> bool {
99 true
100 }
101
102 crate::event::impl_builtin_intrinsic_reporting!(
103 event_detector,
104 event_history,
105 [present_value],
106 reliability,
107 event_detection_enable,
108 ChangeOfStateDetector::ALGORITHM
109 );
110 impl_intrinsic_write_rollback!(
111 event_detector,
112 event_detection_enable,
113 event_history,
114 reliability_inhibit,
115 reliability,
116 out_of_service,
117 reliability_before_out_of_service
118 );
119
120 fn acknowledge_alarm_correlated_internal(
121 &mut self,
122 event_state: EventState,
123 timestamp: &BACnetTimeStamp,
124 ) -> Result<(), Error> {
125 if !self.event_detection_enable {
126 return Err(Error::Protocol {
127 class: ErrorClass::OBJECT.to_raw() as u32,
128 code: ErrorCode::NO_ALARM_CONFIGURED.to_raw() as u32,
129 });
130 }
131 self.event_history.acknowledge_correlated(
132 &mut self.event_detector.acked_transitions,
133 event_state,
134 timestamp,
135 )
136 }
137
138 fn read_property(
139 &self,
140 property: PropertyIdentifier,
141 array_index: Option<u32>,
142 ) -> Result<PropertyValue, Error> {
143 if property == PropertyIdentifier::STATUS_FLAGS {
144 return Ok(common::compute_status_flags(
145 self.status_flags,
146 self.reliability,
147 self.out_of_service,
148 self.event_detector.event_state.to_raw(),
149 ));
150 }
151 if let Some(value) = self.reliability_inhibit.read(property) {
152 return Ok(value);
153 }
154 if let Some(result) = read_common_properties!(self, property, array_index) {
155 return result;
156 }
157 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
158 return Ok(PropertyValue::Boolean(self.event_detection_enable));
159 }
160 if let Some(result) = read_generic_event_properties!(self, property) {
161 return result;
162 }
163 if let Some(result) = self.event_history.read(property, array_index) {
164 return result;
165 }
166 match property {
167 p if p == PropertyIdentifier::OBJECT_TYPE => {
168 Ok(PropertyValue::Enumerated(ObjectType::BINARY_VALUE.to_raw()))
169 }
170 p if p == PropertyIdentifier::PRESENT_VALUE => {
171 Ok(PropertyValue::Enumerated(self.present_value))
172 }
173 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
174 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
175 }
176 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
177 Ok(PropertyValue::Enumerated(self.relinquish_default))
178 }
179 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
180 Ok(common::current_command_priority(&self.priority_array))
181 }
182 p if p == PropertyIdentifier::VALUE_SOURCE => {
183 Ok(self.value_source.value_source.clone())
184 }
185 p if p == PropertyIdentifier::LAST_COMMAND_TIME => Ok(PropertyValue::Unsigned(
186 match self.value_source.last_command_time {
187 BACnetTimeStamp::SequenceNumber(n) => u64::from(n),
188 _ => 0,
189 },
190 )),
191 p if p == PropertyIdentifier::ACTIVE_TEXT => {
192 Ok(PropertyValue::CharacterString(self.active_text.clone()))
193 }
194 p if p == PropertyIdentifier::INACTIVE_TEXT => {
195 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
196 }
197 p if p == PropertyIdentifier::ALARM_VALUE => {
198 Ok(PropertyValue::Enumerated(
201 self.event_detector
202 .alarm_values
203 .first()
204 .copied()
205 .unwrap_or(1),
206 ))
207 }
208 _ => Err(common::unknown_property_error()),
209 }
210 }
211
212 fn write_property(
213 &mut self,
214 property: PropertyIdentifier,
215 array_index: Option<u32>,
216 value: PropertyValue,
217 priority: Option<u8>,
218 ) -> Result<(), Error> {
219 common::write_priority_array_direct!(self, property, array_index, value, |v| {
220 if let PropertyValue::Enumerated(e) = v {
221 if e > 1 {
222 Err(common::value_out_of_range_error())
223 } else {
224 Ok(e)
225 }
226 } else {
227 Err(common::invalid_data_type_error())
228 }
229 });
230 if property == PropertyIdentifier::PRESENT_VALUE {
231 return common::write_priority_array!(self, value, priority, |v| {
232 if let PropertyValue::Enumerated(e) = v {
233 if e > 1 {
234 Err(common::value_out_of_range_error())
235 } else {
236 Ok(e)
237 }
238 } else {
239 Err(common::invalid_data_type_error())
240 }
241 });
242 }
243 if property == PropertyIdentifier::ACTIVE_TEXT {
244 if let PropertyValue::CharacterString(s) = value {
245 self.active_text = s;
246 return Ok(());
247 }
248 return Err(common::invalid_data_type_error());
249 }
250 if property == PropertyIdentifier::INACTIVE_TEXT {
251 if let PropertyValue::CharacterString(s) = value {
252 self.inactive_text = s;
253 return Ok(());
254 }
255 return Err(common::invalid_data_type_error());
256 }
257 if property == PropertyIdentifier::ALARM_VALUE {
258 if let PropertyValue::Enumerated(v) = value {
259 if v > 1 {
260 return Err(common::value_out_of_range_error());
261 }
262 self.event_detector.alarm_values = vec![v];
263 return Ok(());
264 }
265 return Err(common::invalid_data_type_error());
266 }
267 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
268 if let PropertyValue::Boolean(v) = value {
269 self.event_detection_enable = v;
270 if !v {
271 self.event_detector.event_state = bacnet_types::enums::EventState::NORMAL;
272 self.event_detector.acked_transitions = 0b111;
273 self.event_detector.pending = None;
274 self.event_detector.fault_reliability = None;
275 self.event_history.reset();
276 }
277 return Ok(());
278 }
279 return Err(common::invalid_data_type_error());
280 }
281 if property == PropertyIdentifier::RELINQUISH_DEFAULT {
282 if let PropertyValue::Enumerated(e) = value {
283 return self.set_relinquish_default(e);
284 }
285 return Err(common::invalid_data_type_error());
286 }
287 if let Some(result) = write_generic_event_properties!(self, property, value) {
288 return result;
289 }
290 if let Some(result) = self.reliability_inhibit.write_inhibit(
291 &mut self.reliability,
292 self.out_of_service,
293 property,
294 &value,
295 ) {
296 return result;
297 }
298 if let Some(result) = self.reliability_inhibit.write_out_of_service(
299 &mut self.out_of_service,
300 &mut self.reliability,
301 &mut self.reliability_before_out_of_service,
302 property,
303 &value,
304 ) {
305 return result;
306 }
307 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
308 return result;
309 }
310 if let Some(result) = common::write_description(&mut self.description, property, &value) {
311 return result;
312 }
313 if let Some(result) = self.reliability_inhibit.write_client_reliability(
319 self.out_of_service,
320 &mut self.reliability,
321 property,
322 &value,
323 ) {
324 return result;
325 }
326 Err(common::write_access_denied_error())
327 }
328
329 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
330 static PROPS: &[PropertyIdentifier] = &[
331 PropertyIdentifier::OBJECT_IDENTIFIER,
332 PropertyIdentifier::OBJECT_NAME,
333 PropertyIdentifier::DESCRIPTION,
334 PropertyIdentifier::OBJECT_TYPE,
335 PropertyIdentifier::PRESENT_VALUE,
336 PropertyIdentifier::STATUS_FLAGS,
337 PropertyIdentifier::EVENT_STATE,
338 PropertyIdentifier::EVENT_DETECTION_ENABLE,
339 PropertyIdentifier::EVENT_ENABLE,
340 PropertyIdentifier::TIME_DELAY,
341 PropertyIdentifier::TIME_DELAY_NORMAL,
342 PropertyIdentifier::NOTIFY_TYPE,
343 PropertyIdentifier::NOTIFICATION_CLASS,
344 PropertyIdentifier::ACKED_TRANSITIONS,
345 PropertyIdentifier::EVENT_TIME_STAMPS,
346 PropertyIdentifier::EVENT_MESSAGE_TEXTS,
347 PropertyIdentifier::OUT_OF_SERVICE,
348 PropertyIdentifier::PRIORITY_ARRAY,
349 PropertyIdentifier::RELINQUISH_DEFAULT,
350 PropertyIdentifier::CURRENT_COMMAND_PRIORITY,
351 PropertyIdentifier::RELIABILITY,
352 PropertyIdentifier::RELIABILITY_EVALUATION_INHIBIT,
353 PropertyIdentifier::ACTIVE_TEXT,
354 PropertyIdentifier::INACTIVE_TEXT,
355 PropertyIdentifier::ALARM_VALUE,
356 ];
357 Cow::Borrowed(PROPS)
358 }
359
360 fn is_createable(&self) -> bool {
361 true
362 }
363
364 fn set_reliability_internal(&mut self, reliability: u32) -> Result<(), Error> {
365 if self.out_of_service || self.reliability_inhibit.enabled() {
366 return Err(common::write_access_denied_error());
367 }
368 if !common::is_reliability_value_valid(reliability) {
369 return Err(common::value_out_of_range_error());
370 }
371 self.reliability = reliability;
372 Ok(())
373 }
374
375 fn reliability_evaluation_inhibited_internal(&self) -> bool {
376 self.reliability_inhibit.enabled()
377 }
378
379 fn is_writable_property(&self, property: PropertyIdentifier) -> bool {
380 common::is_commandable_property_writable(property)
387 || common::is_common_writable(property)
388 || common::is_generic_event_property_writable(property)
389 || property == PropertyIdentifier::ACTIVE_TEXT
390 || property == PropertyIdentifier::INACTIVE_TEXT
391 || property == PropertyIdentifier::ALARM_VALUE
392 || property == PropertyIdentifier::RELIABILITY
393 || property == PropertyIdentifier::RELIABILITY_EVALUATION_INHIBIT
394 || property == PropertyIdentifier::EVENT_DETECTION_ENABLE
395 }
396}
397
398#[cfg(test)]
399#[path = "tests/value.rs"]
400mod value_tests;