1use super::*;
2use crate::event::CommandFailureDetector;
3use crate::object_profile::{ObjectProfile, ProfileState, TagsPersistence};
4use crate::property_metadata::PropertyMetadata;
5use std::sync::Arc;
6
7mod metadata;
8
9pub struct MultiStateOutputObject {
18 profile: ProfileState,
19 oid: ObjectIdentifier,
20 name: String,
21 description: String,
22 present_value: u32,
23 feedback_value: u32,
24 number_of_states: u32,
25 out_of_service: bool,
26 status_flags: StatusFlags,
27 priority_array: [Option<u32>; 16],
28 relinquish_default: u32,
29 reliability: Reliability,
31 reliability_before_out_of_service: Option<Reliability>,
32 reliability_inhibit: common::ReliabilityInhibitState,
33 reliability_evaluator: MultiStateReliabilityState,
34 event_detection_enable: bool,
35 state_text: Vec<String>,
36 event_detector: CommandFailureDetector,
38 pub(crate) event_history: EventHistory,
39 value_source: crate::command_source::ValueSourceTracking,
41}
42
43impl MultiStateOutputObject {
44 pub fn new(
46 instance: u32,
47 name: impl Into<String>,
48 number_of_states: u32,
49 ) -> Result<Self, Error> {
50 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_OUTPUT, instance)?;
51 require_nonzero_states(number_of_states)?;
52 Ok(Self {
53 profile: ProfileState::default(),
54 oid,
55 name: name.into(),
56 description: String::new(),
57 present_value: 1,
58 feedback_value: 1,
59 number_of_states,
60 out_of_service: false,
61 status_flags: StatusFlags::empty(),
62 priority_array: [None; 16],
63 relinquish_default: 1,
64 reliability: Reliability::NO_FAULT_DETECTED,
65 reliability_before_out_of_service: None,
66 reliability_inhibit: common::ReliabilityInhibitState::default(),
67 reliability_evaluator: MultiStateReliabilityState::default(),
68 event_detection_enable: false,
69 state_text: (1..=number_of_states)
70 .map(|i| format!("State {i}"))
71 .collect(),
72 event_detector: CommandFailureDetector::default(),
73 event_history: EventHistory::default(),
74 value_source: crate::command_source::ValueSourceTracking::default(),
75 })
76 }
77
78 pub fn with_tags_persistence(
82 instance: u32,
83 name: impl Into<String>,
84 number_of_states: u32,
85 persistence: Arc<dyn TagsPersistence>,
86 ) -> Result<Self, Error> {
87 let mut object = Self::new(instance, name, number_of_states)?;
88 object.profile = ProfileState::persistent(object.oid, persistence)?;
89 Ok(object)
90 }
91
92 pub fn set_profile(&mut self, profile: ObjectProfile) -> Result<(), Error> {
97 self.profile.provision(profile)
98 }
99
100 pub fn wait_for_tag_saves(&self) {
103 self.profile.wait_for_saves();
104 }
105
106 pub fn set_description(&mut self, desc: impl Into<String>) {
108 self.description = desc.into();
109 }
110
111 fn recalculate_present_value(&mut self) {
112 self.present_value =
113 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
114 let _ = self.recompute_reliability();
115 }
116
117 fn held_states(&self) -> impl Iterator<Item = u32> + '_ {
123 self.priority_array
124 .iter()
125 .flatten()
126 .copied()
127 .chain([self.present_value, self.relinquish_default])
128 }
129
130 fn configuration_invalid(&self) -> bool {
131 let is_invalid = |value: u32| !(1..=self.number_of_states).contains(&value);
132 self.priority_array
133 .iter()
134 .flatten()
135 .copied()
136 .any(is_invalid)
137 || is_invalid(self.relinquish_default)
138 || is_invalid(self.feedback_value)
139 }
140
141 fn recompute_reliability(&mut self) -> ReliabilityEvaluation {
142 if self.out_of_service || self.reliability_inhibit.enabled() {
143 return ReliabilityEvaluation::Unchanged;
144 }
145 let configuration_invalid = self.configuration_invalid();
146 self.reliability_evaluator.evaluate(
147 configuration_invalid,
148 self.present_value,
149 self.number_of_states,
150 &mut self.reliability,
151 )
152 }
153
154 pub fn set_number_of_states(&mut self, number_of_states: u32) -> Result<(), Error> {
160 resize_state_text(
161 &mut self.number_of_states,
162 &mut self.state_text,
163 number_of_states,
164 )?;
165 let _ = self.recompute_reliability();
166 Ok(())
167 }
168
169 pub fn set_relinquish_default(&mut self, value: u32) -> Result<(), Error> {
184 if value < 1 || value > self.number_of_states {
185 return Err(common::value_out_of_range_error());
186 }
187 self.relinquish_default = value;
188 self.recalculate_present_value();
189 Ok(())
190 }
191}
192
193impl BACnetObject for MultiStateOutputObject {
194 fn object_identifier(&self) -> ObjectIdentifier {
195 self.oid
196 }
197
198 fn object_name(&self) -> &str {
199 &self.name
200 }
201
202 fn supports_cov(&self) -> bool {
203 true
204 }
205
206 crate::event::impl_builtin_intrinsic_reporting!(
207 event_detector,
208 event_history,
209 [present_value, feedback_value],
210 reliability,
211 event_detection_enable,
212 CommandFailureDetector::ALGORITHM
213 );
214
215 fn acknowledge_alarm_correlated_internal(
216 &mut self,
217 event_state: EventState,
218 timestamp: &BACnetTimeStamp,
219 ) -> Result<(), Error> {
220 if !self.event_detection_enable {
221 return Err(Error::Protocol {
222 class: ErrorClass::OBJECT.to_raw() as u32,
223 code: ErrorCode::NO_ALARM_CONFIGURED.to_raw() as u32,
224 });
225 }
226 self.event_history.acknowledge_correlated(
227 &mut self.event_detector.acked_transitions,
228 event_state,
229 timestamp,
230 )
231 }
232
233 fn read_property(
234 &self,
235 property: PropertyIdentifier,
236 array_index: Option<u32>,
237 ) -> Result<PropertyValue, Error> {
238 if let Some(result) = self
239 .value_source
240 .read(property, array_index, &self.priority_array)
241 {
242 return result;
243 }
244
245 if property == PropertyIdentifier::STATUS_FLAGS {
246 return Ok(common::compute_status_flags(
247 self.status_flags,
248 self.reliability,
249 self.out_of_service,
250 self.event_detector.event_state,
251 ));
252 }
253 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
254 return Ok(PropertyValue::Boolean(self.event_detection_enable));
255 }
256 if let Some(value) = self.reliability_inhibit.read(property) {
257 return Ok(value);
258 }
259 if let Some(result) = read_common_properties!(self, property, array_index) {
260 return result;
261 }
262 if let Some(result) = read_generic_event_properties!(self, property) {
263 return result;
264 }
265 if let Some(result) = self.event_history.read(property, array_index) {
266 return result;
267 }
268 if let Some(result) = self.profile.read(property, array_index) {
269 return result;
270 }
271 match property {
272 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
273 ObjectType::MULTI_STATE_OUTPUT.to_raw(),
274 )),
275 p if p == PropertyIdentifier::PRESENT_VALUE => {
276 Ok(PropertyValue::Unsigned(self.present_value as u64))
277 }
278 p if p == PropertyIdentifier::FEEDBACK_VALUE => {
279 Ok(PropertyValue::Unsigned(self.feedback_value as u64))
280 }
281 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
282 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
283 }
284 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
285 common::read_priority_array!(self, array_index, |v: u32| PropertyValue::Unsigned(
286 v as u64
287 ))
288 }
289 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
290 Ok(PropertyValue::Unsigned(self.relinquish_default as u64))
291 }
292 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
293 Ok(common::current_command_priority(&self.priority_array))
294 }
295 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
296 None => Ok(PropertyValue::List(
297 self.state_text
298 .iter()
299 .map(|s| PropertyValue::CharacterString(s.clone()))
300 .collect(),
301 )),
302 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
303 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
304 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
305 ),
306 _ => Err(common::invalid_array_index_error()),
307 },
308 _ => Err(common::unknown_property_error()),
309 }
310 }
311
312 fn write_property_from(
313 &mut self,
314 property: PropertyIdentifier,
315 array_index: Option<u32>,
316 value: PropertyValue,
317 priority: Option<u8>,
318 origin: &crate::command_source::CommandOrigin,
319 ) -> Result<(), Error> {
320 if matches!(
321 property,
322 PropertyIdentifier::PRESENT_VALUE | PropertyIdentifier::VALUE_SOURCE
323 ) && array_index.is_some()
324 {
325 return Err(common::property_is_not_an_array_error());
326 }
327 if property == PropertyIdentifier::VALUE_SOURCE {
328 return self.value_source.correct(value, priority, origin);
329 }
330 if property == PropertyIdentifier::PRESENT_VALUE {
331 let num_states = self.number_of_states;
332 return crate::command_source::write_sourced_priority!(
333 self,
334 value,
335 priority,
336 origin,
337 |v| {
338 if let PropertyValue::Unsigned(u) = v {
339 if u < 1 || u > num_states as u64 {
340 Err(common::value_out_of_range_error())
341 } else {
342 Ok(u as u32)
343 }
344 } else {
345 Err(common::invalid_data_type_error())
346 }
347 }
348 );
349 }
350 self.write_property(property, array_index, value, priority)
351 }
352
353 fn write_property(
354 &mut self,
355 property: PropertyIdentifier,
356 array_index: Option<u32>,
357 value: PropertyValue,
358 _priority: Option<u8>,
359 ) -> Result<(), Error> {
360 if matches!(
361 property,
362 PropertyIdentifier::PRESENT_VALUE | PropertyIdentifier::VALUE_SOURCE
363 ) {
364 return Err(common::write_access_denied_error());
365 }
366 if property == PropertyIdentifier::FEEDBACK_VALUE {
367 if let PropertyValue::Unsigned(u) = value {
368 self.feedback_value = common::u64_to_u32(u)?;
385 let _ = self.recompute_reliability();
386 return Ok(());
387 }
388 return Err(common::invalid_data_type_error());
389 }
390 if property == PropertyIdentifier::STATE_TEXT {
391 let held: Vec<u32> = self.held_states().collect();
393 write_state_text(
394 &mut self.number_of_states,
395 &mut self.state_text,
396 held,
397 array_index,
398 value,
399 )?;
400 let _ = self.recompute_reliability();
401 return Ok(());
402 }
403 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
404 if let PropertyValue::Boolean(v) = value {
405 self.event_detection_enable = v;
406 if !v {
407 self.event_detector.event_state = bacnet_types::enums::EventState::NORMAL;
408 self.event_detector.acked_transitions =
409 bacnet_types::bitstring::EventTransitionBits::all();
410 self.event_detector.pending = None;
411 self.event_detector.fault_reliability = None;
412 self.event_history.reset();
413 }
414 return Ok(());
415 }
416 return Err(common::invalid_data_type_error());
417 }
418 if let Some(result) =
420 self.event_history
421 .write(property, array_index, &value, self.event_detection_enable)
422 {
423 return result;
424 }
425 if let Some(result) = write_generic_event_properties!(self, property, value) {
426 return result;
427 }
428 if let Some(result) = self.reliability_inhibit.write_inhibit(
429 &mut self.reliability,
430 self.out_of_service,
431 property,
432 &value,
433 ) {
434 result?;
435 let _ = self.recompute_reliability();
436 return Ok(());
437 }
438 if let Some(result) = self.reliability_inhibit.write_out_of_service(
439 &mut self.out_of_service,
440 &mut self.reliability,
441 &mut self.reliability_before_out_of_service,
442 property,
443 &value,
444 ) {
445 if result? == crate::reliability_inhibit::OutOfServiceWrite::Applied {
446 let _ = self.recompute_reliability();
447 }
448 return Ok(());
449 }
450 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
451 return result;
452 }
453 if let Some(result) = common::write_description(&mut self.description, property, &value) {
454 return result;
455 }
456 if let Some(result) = self.reliability_inhibit.write_client_reliability(
461 self.out_of_service,
462 &mut self.reliability,
463 property,
464 &value,
465 ) {
466 return result;
467 }
468 if property == PropertyIdentifier::RELINQUISH_DEFAULT {
469 if let PropertyValue::Unsigned(u) = value {
470 let v = common::u64_to_u32(u)?;
471 return self.set_relinquish_default(v);
472 }
473 return Err(common::invalid_data_type_error());
474 }
475 if let Some(result) = self.profile.write(property, array_index, &value) {
476 return result;
477 }
478 Err(crate::common::unhandled_write_error(
479 self.property_metadata().as_ref(),
480 property,
481 array_index,
482 ))
483 }
484
485 fn durable_writes_internal(&mut self) -> Option<&mut dyn crate::durable::DurableWrites> {
486 self.profile.capability()
487 }
488
489 fn advance_monotonic_time_internal(&mut self, now: std::time::Duration) -> bool {
490 self.profile.expire(now);
491 false
492 }
493
494 fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
495 metadata::for_object(self)
496 }
497
498 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
499 crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
500 }
501
502 fn is_createable(&self) -> bool {
503 true
504 }
505 fn creation_only_properties(&self) -> &'static [PropertyIdentifier] {
506 CREATION_ONLY
507 }
508 fn initialize_property(
509 &mut self,
510 property: PropertyIdentifier,
511 value: PropertyValue,
512 ) -> Result<(), Error> {
513 let held: Vec<u32> = self.held_states().collect();
514 initialize_states(
515 &mut self.number_of_states,
516 &mut self.state_text,
517 held,
518 property,
519 value,
520 )?;
521 let _ = self.recompute_reliability();
522 Ok(())
523 }
524 fn set_reliability_internal(&mut self, reliability: Reliability) -> Result<(), Error> {
525 if self.out_of_service || self.reliability_inhibit.enabled() {
526 return Err(common::write_access_denied_error());
527 }
528 if !common::is_reliability_value_valid(reliability) {
529 return Err(common::value_out_of_range_error());
530 }
531 self.reliability = reliability;
532 self.reliability_evaluator.clear_ownership();
533 Ok(())
534 }
535
536 fn evaluate_reliability_internal(&mut self) -> Result<ReliabilityEvaluation, Error> {
537 Ok(self.recompute_reliability())
538 }
539
540 fn reliability_evaluation_inhibited_internal(&self) -> bool {
541 self.reliability_inhibit.enabled()
542 }
543}
544
545#[cfg(test)]
546#[path = "output/tests.rs"]
547mod command_failure_tests;
548
549#[cfg(test)]
550mod reliability_evaluator_tests;