1use bacnet_types::constructed::{BACnetDeviceObjectPropertyReference, FaultParameters};
4use bacnet_types::enums::{ObjectType, PropertyIdentifier};
5use bacnet_types::error::Error;
6use bacnet_types::primitives::{ObjectIdentifier, PropertyValue, StatusFlags};
7use std::borrow::Cow;
8
9use crate::common::{self, read_common_properties};
10use crate::traits::BACnetObject;
11
12pub struct EventEnrollmentObject {
18 oid: ObjectIdentifier,
19 name: String,
20 description: String,
21 event_type: u32,
22 notify_type: u32,
23 event_parameters: Vec<u8>,
24 object_property_reference: Option<BACnetDeviceObjectPropertyReference>,
25 event_state: u32,
26 event_enable: u8,
27 acked_transitions: u8,
28 notification_class: u32,
29 fault_parameters: Option<FaultParameters>,
30 status_flags: StatusFlags,
31 out_of_service: bool,
32 reliability: u32,
33}
34
35impl EventEnrollmentObject {
36 pub fn new(instance: u32, name: impl Into<String>, event_type: u32) -> Result<Self, Error> {
40 let oid = ObjectIdentifier::new(ObjectType::EVENT_ENROLLMENT, instance)?;
41 Ok(Self {
42 oid,
43 name: name.into(),
44 description: String::new(),
45 event_type,
46 notify_type: 0,
47 event_parameters: Vec::new(),
48 object_property_reference: None,
49 event_state: 0,
50 event_enable: 0b111,
51 acked_transitions: 0b111,
52 notification_class: 0,
53 fault_parameters: None,
54 status_flags: StatusFlags::empty(),
55 out_of_service: false,
56 reliability: 0,
57 })
58 }
59
60 pub fn set_description(&mut self, desc: impl Into<String>) {
62 self.description = desc.into();
63 }
64
65 pub fn set_object_property_reference(
67 &mut self,
68 reference: Option<BACnetDeviceObjectPropertyReference>,
69 ) {
70 self.object_property_reference = reference;
71 }
72
73 pub fn set_event_parameters(&mut self, params: Vec<u8>) {
75 self.event_parameters = params;
76 }
77
78 pub fn set_fault_parameters(&mut self, fp: Option<FaultParameters>) {
80 self.fault_parameters = fp;
81 }
82
83 pub fn set_event_state(&mut self, state: u32) {
85 self.event_state = state;
86 }
87
88 pub fn set_notification_class(&mut self, nc: u32) {
90 self.notification_class = nc;
91 }
92
93 pub fn set_event_enable(&mut self, enable: u8) {
95 self.event_enable = enable & 0x07;
96 }
97}
98
99impl BACnetObject for EventEnrollmentObject {
100 fn object_identifier(&self) -> ObjectIdentifier {
101 self.oid
102 }
103
104 fn object_name(&self) -> &str {
105 &self.name
106 }
107
108 fn read_property(
109 &self,
110 property: PropertyIdentifier,
111 array_index: Option<u32>,
112 ) -> Result<PropertyValue, Error> {
113 if let Some(result) = read_common_properties!(self, property, array_index) {
114 return result;
115 }
116 match property {
117 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
118 ObjectType::EVENT_ENROLLMENT.to_raw(),
119 )),
120 p if p == PropertyIdentifier::EVENT_TYPE => {
121 Ok(PropertyValue::Enumerated(self.event_type))
122 }
123 p if p == PropertyIdentifier::NOTIFY_TYPE => {
124 Ok(PropertyValue::Enumerated(self.notify_type))
125 }
126 p if p == PropertyIdentifier::EVENT_PARAMETERS => {
127 Ok(PropertyValue::OctetString(self.event_parameters.clone()))
128 }
129 p if p == PropertyIdentifier::OBJECT_PROPERTY_REFERENCE => {
130 match &self.object_property_reference {
131 None => Ok(PropertyValue::Null),
132 Some(r) => Ok(PropertyValue::List(vec![
133 PropertyValue::ObjectIdentifier(r.object_identifier),
134 PropertyValue::Unsigned(r.property_identifier as u64),
135 match r.property_array_index {
136 Some(idx) => PropertyValue::Unsigned(idx as u64),
137 None => PropertyValue::Null,
138 },
139 match r.device_identifier {
140 Some(dev) => PropertyValue::ObjectIdentifier(dev),
141 None => PropertyValue::Null,
142 },
143 ])),
144 }
145 }
146 p if p == PropertyIdentifier::EVENT_STATE => {
147 Ok(PropertyValue::Enumerated(self.event_state))
148 }
149 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
150 unused_bits: 5,
151 data: vec![self.event_enable << 5],
152 }),
153 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
154 unused_bits: 5,
155 data: vec![self.acked_transitions << 5],
156 }),
157 p if p == PropertyIdentifier::NOTIFICATION_CLASS => {
158 Ok(PropertyValue::Unsigned(self.notification_class as u64))
159 }
160 p if p == PropertyIdentifier::FAULT_PARAMETERS => match &self.fault_parameters {
161 None => Ok(PropertyValue::Null),
162 Some(fp) => {
163 let variant_tag = match fp {
164 FaultParameters::FaultNone => 0u64,
165 FaultParameters::FaultCharacterString { .. } => 1,
166 FaultParameters::FaultExtended { .. } => 2,
167 FaultParameters::FaultLifeSafety { .. } => 3,
168 FaultParameters::FaultState { .. } => 4,
169 FaultParameters::FaultStatusFlags { .. } => 5,
170 FaultParameters::FaultOutOfRange { .. } => 6,
171 FaultParameters::FaultListed { .. } => 7,
172 };
173 Ok(PropertyValue::Unsigned(variant_tag))
174 }
175 },
176 _ => Err(common::unknown_property_error()),
177 }
178 }
179
180 fn write_property(
181 &mut self,
182 property: PropertyIdentifier,
183 _array_index: Option<u32>,
184 value: PropertyValue,
185 _priority: Option<u8>,
186 ) -> Result<(), Error> {
187 if property == PropertyIdentifier::NOTIFY_TYPE {
188 if let PropertyValue::Enumerated(v) = value {
189 self.notify_type = v;
190 return Ok(());
191 }
192 return Err(common::invalid_data_type_error());
193 }
194 if property == PropertyIdentifier::NOTIFICATION_CLASS {
195 if let PropertyValue::Unsigned(v) = value {
196 self.notification_class = common::u64_to_u32(v)?;
197 return Ok(());
198 }
199 return Err(common::invalid_data_type_error());
200 }
201 if property == PropertyIdentifier::EVENT_ENABLE {
202 if let PropertyValue::BitString { data, .. } = &value {
203 if let Some(&byte) = data.first() {
204 self.event_enable = byte >> 5;
205 return Ok(());
206 }
207 return Err(common::invalid_data_type_error());
208 }
209 return Err(common::invalid_data_type_error());
210 }
211 if property == PropertyIdentifier::EVENT_STATE {
212 if let PropertyValue::Enumerated(v) = value {
213 self.event_state = v;
214 return Ok(());
215 }
216 return Err(common::invalid_data_type_error());
217 }
218 if property == PropertyIdentifier::EVENT_PARAMETERS {
219 if let PropertyValue::OctetString(bytes) = value {
220 self.event_parameters = bytes;
221 return Ok(());
222 }
223 return Err(common::invalid_data_type_error());
224 }
225 if let Some(result) =
226 common::write_out_of_service(&mut self.out_of_service, property, &value)
227 {
228 return result;
229 }
230 if let Some(result) = common::write_description(&mut self.description, property, &value) {
231 return result;
232 }
233 Err(common::write_access_denied_error())
234 }
235
236 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
237 static PROPS: &[PropertyIdentifier] = &[
238 PropertyIdentifier::OBJECT_IDENTIFIER,
239 PropertyIdentifier::OBJECT_NAME,
240 PropertyIdentifier::DESCRIPTION,
241 PropertyIdentifier::OBJECT_TYPE,
242 PropertyIdentifier::EVENT_TYPE,
243 PropertyIdentifier::NOTIFY_TYPE,
244 PropertyIdentifier::EVENT_PARAMETERS,
245 PropertyIdentifier::OBJECT_PROPERTY_REFERENCE,
246 PropertyIdentifier::EVENT_STATE,
247 PropertyIdentifier::EVENT_ENABLE,
248 PropertyIdentifier::ACKED_TRANSITIONS,
249 PropertyIdentifier::NOTIFICATION_CLASS,
250 PropertyIdentifier::FAULT_PARAMETERS,
251 PropertyIdentifier::STATUS_FLAGS,
252 PropertyIdentifier::OUT_OF_SERVICE,
253 PropertyIdentifier::RELIABILITY,
254 ];
255 Cow::Borrowed(PROPS)
256 }
257}
258
259pub struct AlertEnrollmentObject {
269 oid: ObjectIdentifier,
270 name: String,
271 description: String,
272 status_flags: StatusFlags,
273 out_of_service: bool,
274 reliability: u32,
275 pub present_value: u32,
277 pub event_detection_enable: bool,
279 pub event_enable: u8,
281 pub notification_class: u32,
283}
284
285impl AlertEnrollmentObject {
286 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
288 let oid = ObjectIdentifier::new(ObjectType::ALERT_ENROLLMENT, instance)?;
289 Ok(Self {
290 oid,
291 name: name.into(),
292 description: String::new(),
293 status_flags: StatusFlags::empty(),
294 out_of_service: false,
295 reliability: 0,
296 present_value: 0,
297 event_detection_enable: true,
298 event_enable: 0b111,
299 notification_class: 0,
300 })
301 }
302}
303
304impl BACnetObject for AlertEnrollmentObject {
305 fn object_identifier(&self) -> ObjectIdentifier {
306 self.oid
307 }
308
309 fn object_name(&self) -> &str {
310 &self.name
311 }
312
313 fn read_property(
314 &self,
315 property: PropertyIdentifier,
316 array_index: Option<u32>,
317 ) -> Result<PropertyValue, Error> {
318 if let Some(result) = read_common_properties!(self, property, array_index) {
319 return result;
320 }
321 match property {
322 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
323 ObjectType::ALERT_ENROLLMENT.to_raw(),
324 )),
325 p if p == PropertyIdentifier::PRESENT_VALUE => {
326 Ok(PropertyValue::Enumerated(self.present_value))
327 }
328 p if p == PropertyIdentifier::EVENT_DETECTION_ENABLE => {
329 Ok(PropertyValue::Boolean(self.event_detection_enable))
330 }
331 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
332 unused_bits: 5,
333 data: vec![self.event_enable << 5],
334 }),
335 p if p == PropertyIdentifier::NOTIFICATION_CLASS => {
336 Ok(PropertyValue::Unsigned(self.notification_class as u64))
337 }
338 _ => Err(common::unknown_property_error()),
339 }
340 }
341
342 fn write_property(
343 &mut self,
344 property: PropertyIdentifier,
345 _array_index: Option<u32>,
346 value: PropertyValue,
347 _priority: Option<u8>,
348 ) -> Result<(), Error> {
349 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
350 if let PropertyValue::Boolean(v) = value {
351 self.event_detection_enable = v;
352 return Ok(());
353 }
354 return Err(common::invalid_data_type_error());
355 }
356 if property == PropertyIdentifier::EVENT_ENABLE {
357 if let PropertyValue::BitString { data, .. } = &value {
358 if let Some(&byte) = data.first() {
359 self.event_enable = byte >> 5;
360 return Ok(());
361 }
362 return Err(common::invalid_data_type_error());
363 }
364 return Err(common::invalid_data_type_error());
365 }
366 if property == PropertyIdentifier::NOTIFICATION_CLASS {
367 if let PropertyValue::Unsigned(v) = value {
368 self.notification_class = common::u64_to_u32(v)?;
369 return Ok(());
370 }
371 return Err(common::invalid_data_type_error());
372 }
373 if let Some(result) =
374 common::write_out_of_service(&mut self.out_of_service, property, &value)
375 {
376 return result;
377 }
378 if let Some(result) = common::write_description(&mut self.description, property, &value) {
379 return result;
380 }
381 Err(common::write_access_denied_error())
382 }
383
384 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
385 static PROPS: &[PropertyIdentifier] = &[
386 PropertyIdentifier::OBJECT_IDENTIFIER,
387 PropertyIdentifier::OBJECT_NAME,
388 PropertyIdentifier::DESCRIPTION,
389 PropertyIdentifier::OBJECT_TYPE,
390 PropertyIdentifier::PRESENT_VALUE,
391 PropertyIdentifier::EVENT_DETECTION_ENABLE,
392 PropertyIdentifier::EVENT_ENABLE,
393 PropertyIdentifier::NOTIFICATION_CLASS,
394 PropertyIdentifier::STATUS_FLAGS,
395 PropertyIdentifier::OUT_OF_SERVICE,
396 PropertyIdentifier::RELIABILITY,
397 ];
398 Cow::Borrowed(PROPS)
399 }
400}
401
402#[cfg(test)]
403mod tests {
404 use super::*;
405
406 #[test]
407 fn create_event_enrollment() {
408 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
409 assert_eq!(
410 ee.object_identifier().object_type(),
411 ObjectType::EVENT_ENROLLMENT
412 );
413 assert_eq!(ee.object_identifier().instance_number(), 1);
414 assert_eq!(ee.object_name(), "EE-1");
415 }
416
417 #[test]
418 fn read_object_type() {
419 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
420 let val = ee
421 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
422 .unwrap();
423 assert_eq!(
424 val,
425 PropertyValue::Enumerated(ObjectType::EVENT_ENROLLMENT.to_raw())
426 );
427 }
428
429 #[test]
430 fn read_event_type() {
431 let ee = EventEnrollmentObject::new(1, "EE-1", 3).unwrap();
432 let val = ee
433 .read_property(PropertyIdentifier::EVENT_TYPE, None)
434 .unwrap();
435 assert_eq!(val, PropertyValue::Enumerated(3));
436 }
437
438 #[test]
439 fn read_event_enable() {
440 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
441 let val = ee
442 .read_property(PropertyIdentifier::EVENT_ENABLE, None)
443 .unwrap();
444 assert_eq!(
446 val,
447 PropertyValue::BitString {
448 unused_bits: 5,
449 data: vec![0b1110_0000],
450 }
451 );
452 }
453
454 #[test]
455 fn read_notification_class() {
456 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
457 let val = ee
458 .read_property(PropertyIdentifier::NOTIFICATION_CLASS, None)
459 .unwrap();
460 assert_eq!(val, PropertyValue::Unsigned(0));
461 }
462
463 #[test]
464 fn write_notify_type() {
465 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
466 ee.write_property(
467 PropertyIdentifier::NOTIFY_TYPE,
468 None,
469 PropertyValue::Enumerated(1),
470 None,
471 )
472 .unwrap();
473 let val = ee
474 .read_property(PropertyIdentifier::NOTIFY_TYPE, None)
475 .unwrap();
476 assert_eq!(val, PropertyValue::Enumerated(1));
477 }
478
479 #[test]
480 fn write_notify_type_wrong_type() {
481 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
482 let result = ee.write_property(
483 PropertyIdentifier::NOTIFY_TYPE,
484 None,
485 PropertyValue::Real(1.0),
486 None,
487 );
488 assert!(result.is_err());
489 }
490
491 #[test]
492 fn read_acked_transitions() {
493 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
494 let val = ee
495 .read_property(PropertyIdentifier::ACKED_TRANSITIONS, None)
496 .unwrap();
497 assert_eq!(
499 val,
500 PropertyValue::BitString {
501 unused_bits: 5,
502 data: vec![0b1110_0000],
503 }
504 );
505 }
506
507 #[test]
508 fn read_object_property_reference_none() {
509 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
510 let val = ee
511 .read_property(PropertyIdentifier::OBJECT_PROPERTY_REFERENCE, None)
512 .unwrap();
513 assert_eq!(val, PropertyValue::Null);
514 }
515
516 #[test]
517 fn read_object_property_reference_some() {
518 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
519 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 5).unwrap();
520 ee.set_object_property_reference(Some(BACnetDeviceObjectPropertyReference {
521 object_identifier: ai_oid,
522 property_identifier: PropertyIdentifier::PRESENT_VALUE.to_raw(),
523 property_array_index: None,
524 device_identifier: None,
525 }));
526 let val = ee
527 .read_property(PropertyIdentifier::OBJECT_PROPERTY_REFERENCE, None)
528 .unwrap();
529 if let PropertyValue::List(fields) = val {
530 assert_eq!(fields.len(), 4);
531 assert_eq!(fields[0], PropertyValue::ObjectIdentifier(ai_oid));
532 assert_eq!(
533 fields[1],
534 PropertyValue::Unsigned(PropertyIdentifier::PRESENT_VALUE.to_raw() as u64)
535 );
536 assert_eq!(fields[2], PropertyValue::Null); assert_eq!(fields[3], PropertyValue::Null); } else {
539 panic!("Expected List");
540 }
541 }
542
543 #[test]
544 fn write_notification_class() {
545 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
546 ee.write_property(
547 PropertyIdentifier::NOTIFICATION_CLASS,
548 None,
549 PropertyValue::Unsigned(42),
550 None,
551 )
552 .unwrap();
553 let val = ee
554 .read_property(PropertyIdentifier::NOTIFICATION_CLASS, None)
555 .unwrap();
556 assert_eq!(val, PropertyValue::Unsigned(42));
557 }
558
559 #[test]
560 fn write_event_enable() {
561 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
562 ee.write_property(
564 PropertyIdentifier::EVENT_ENABLE,
565 None,
566 PropertyValue::BitString {
567 unused_bits: 5,
568 data: vec![0b1000_0000],
569 },
570 None,
571 )
572 .unwrap();
573 let val = ee
574 .read_property(PropertyIdentifier::EVENT_ENABLE, None)
575 .unwrap();
576 assert_eq!(
577 val,
578 PropertyValue::BitString {
579 unused_bits: 5,
580 data: vec![0b1000_0000],
581 }
582 );
583 }
584
585 #[test]
586 fn property_list_complete() {
587 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
588 let props = ee.property_list();
589 assert!(props.contains(&PropertyIdentifier::EVENT_TYPE));
590 assert!(props.contains(&PropertyIdentifier::NOTIFY_TYPE));
591 assert!(props.contains(&PropertyIdentifier::EVENT_PARAMETERS));
592 assert!(props.contains(&PropertyIdentifier::OBJECT_PROPERTY_REFERENCE));
593 assert!(props.contains(&PropertyIdentifier::EVENT_STATE));
594 assert!(props.contains(&PropertyIdentifier::EVENT_ENABLE));
595 assert!(props.contains(&PropertyIdentifier::ACKED_TRANSITIONS));
596 assert!(props.contains(&PropertyIdentifier::NOTIFICATION_CLASS));
597 }
598
599 #[test]
600 fn write_event_parameters() {
601 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
602 let params = vec![0x01, 0x02, 0x03];
603 ee.write_property(
604 PropertyIdentifier::EVENT_PARAMETERS,
605 None,
606 PropertyValue::OctetString(params.clone()),
607 None,
608 )
609 .unwrap();
610 let val = ee
611 .read_property(PropertyIdentifier::EVENT_PARAMETERS, None)
612 .unwrap();
613 assert_eq!(val, PropertyValue::OctetString(params));
614 }
615
616 #[test]
617 fn read_event_state_default() {
618 let ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
619 let val = ee
620 .read_property(PropertyIdentifier::EVENT_STATE, None)
621 .unwrap();
622 assert_eq!(val, PropertyValue::Enumerated(0)); }
624
625 #[test]
626 fn write_unknown_property_denied() {
627 let mut ee = EventEnrollmentObject::new(1, "EE-1", 0).unwrap();
628 let result = ee.write_property(
629 PropertyIdentifier::PRESENT_VALUE,
630 None,
631 PropertyValue::Real(1.0),
632 None,
633 );
634 assert!(result.is_err());
635 }
636
637 #[test]
642 fn fault_parameters_default_none() {
643 let ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
644 let val = ee
645 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
646 .unwrap();
647 assert_eq!(val, PropertyValue::Null);
648 }
649
650 #[test]
651 fn fault_parameters_none_variant() {
652 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
653 ee.set_fault_parameters(Some(FaultParameters::FaultNone));
654 let val = ee
655 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
656 .unwrap();
657 assert_eq!(val, PropertyValue::Unsigned(0));
658 }
659
660 #[test]
661 fn fault_parameters_character_string() {
662 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
663 ee.set_fault_parameters(Some(FaultParameters::FaultCharacterString {
664 fault_values: vec!["alarm".to_string(), "critical".to_string()],
665 }));
666 let val = ee
667 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
668 .unwrap();
669 assert_eq!(val, PropertyValue::Unsigned(1));
670 }
671
672 #[test]
673 fn fault_parameters_extended() {
674 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
675 ee.set_fault_parameters(Some(FaultParameters::FaultExtended {
676 vendor_id: 42,
677 extended_fault_type: 7,
678 parameters: vec![0x01, 0x02],
679 }));
680 let val = ee
681 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
682 .unwrap();
683 assert_eq!(val, PropertyValue::Unsigned(2));
684 }
685
686 #[test]
687 fn fault_parameters_life_safety() {
688 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
689 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap();
690 ee.set_fault_parameters(Some(FaultParameters::FaultLifeSafety {
691 fault_values: vec![1, 2, 3],
692 mode_for_reference: BACnetDeviceObjectPropertyReference {
693 object_identifier: ai_oid,
694 property_identifier: PropertyIdentifier::PRESENT_VALUE.to_raw(),
695 property_array_index: None,
696 device_identifier: None,
697 },
698 }));
699 let val = ee
700 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
701 .unwrap();
702 assert_eq!(val, PropertyValue::Unsigned(3));
703 }
704
705 #[test]
706 fn fault_parameters_state() {
707 use bacnet_types::constructed::BACnetPropertyStates;
708 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
709 ee.set_fault_parameters(Some(FaultParameters::FaultState {
710 fault_values: vec![BACnetPropertyStates::BooleanValue(true)],
711 }));
712 let val = ee
713 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
714 .unwrap();
715 assert_eq!(val, PropertyValue::Unsigned(4));
716 }
717
718 #[test]
719 fn fault_parameters_status_flags() {
720 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
721 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap();
722 ee.set_fault_parameters(Some(FaultParameters::FaultStatusFlags {
723 reference: BACnetDeviceObjectPropertyReference {
724 object_identifier: ai_oid,
725 property_identifier: PropertyIdentifier::STATUS_FLAGS.to_raw(),
726 property_array_index: None,
727 device_identifier: None,
728 },
729 }));
730 let val = ee
731 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
732 .unwrap();
733 assert_eq!(val, PropertyValue::Unsigned(5));
734 }
735
736 #[test]
737 fn fault_parameters_out_of_range() {
738 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
739 ee.set_fault_parameters(Some(FaultParameters::FaultOutOfRange {
740 min_normal: 0.0,
741 max_normal: 100.0,
742 }));
743 let val = ee
744 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
745 .unwrap();
746 assert_eq!(val, PropertyValue::Unsigned(6));
747 }
748
749 #[test]
750 fn fault_parameters_listed() {
751 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
752 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap();
753 ee.set_fault_parameters(Some(FaultParameters::FaultListed {
754 reference: BACnetDeviceObjectPropertyReference {
755 object_identifier: ai_oid,
756 property_identifier: PropertyIdentifier::PRESENT_VALUE.to_raw(),
757 property_array_index: None,
758 device_identifier: None,
759 },
760 }));
761 let val = ee
762 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
763 .unwrap();
764 assert_eq!(val, PropertyValue::Unsigned(7));
765 }
766
767 #[test]
768 fn fault_parameters_in_property_list() {
769 let ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
770 let props = ee.property_list();
771 assert!(props.contains(&PropertyIdentifier::FAULT_PARAMETERS));
772 }
773
774 #[test]
775 fn fault_parameters_clear() {
776 let mut ee = EventEnrollmentObject::new(1, "EE-FP", 0).unwrap();
777 ee.set_fault_parameters(Some(FaultParameters::FaultNone));
778 let val = ee
779 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
780 .unwrap();
781 assert_eq!(val, PropertyValue::Unsigned(0));
782
783 ee.set_fault_parameters(None);
785 let val = ee
786 .read_property(PropertyIdentifier::FAULT_PARAMETERS, None)
787 .unwrap();
788 assert_eq!(val, PropertyValue::Null);
789 }
790
791 #[test]
796 fn alert_enrollment_create() {
797 let ae = AlertEnrollmentObject::new(1, "AE-1").unwrap();
798 assert_eq!(
799 ae.object_identifier().object_type(),
800 ObjectType::ALERT_ENROLLMENT
801 );
802 assert_eq!(ae.object_identifier().instance_number(), 1);
803 assert_eq!(ae.object_name(), "AE-1");
804 }
805
806 #[test]
807 fn alert_enrollment_object_type() {
808 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
809 let val = ae
810 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
811 .unwrap();
812 assert_eq!(
813 val,
814 PropertyValue::Enumerated(ObjectType::ALERT_ENROLLMENT.to_raw())
815 );
816 }
817
818 #[test]
819 fn alert_enrollment_present_value_default() {
820 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
821 let val = ae
822 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
823 .unwrap();
824 assert_eq!(val, PropertyValue::Enumerated(0));
825 }
826
827 #[test]
828 fn alert_enrollment_event_detection_enable() {
829 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
830 let val = ae
831 .read_property(PropertyIdentifier::EVENT_DETECTION_ENABLE, None)
832 .unwrap();
833 assert_eq!(val, PropertyValue::Boolean(true));
834 }
835
836 #[test]
837 fn alert_enrollment_write_event_detection_enable() {
838 let mut ae = AlertEnrollmentObject::new(1, "AE").unwrap();
839 ae.write_property(
840 PropertyIdentifier::EVENT_DETECTION_ENABLE,
841 None,
842 PropertyValue::Boolean(false),
843 None,
844 )
845 .unwrap();
846 let val = ae
847 .read_property(PropertyIdentifier::EVENT_DETECTION_ENABLE, None)
848 .unwrap();
849 assert_eq!(val, PropertyValue::Boolean(false));
850 }
851
852 #[test]
853 fn alert_enrollment_event_enable() {
854 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
855 let val = ae
856 .read_property(PropertyIdentifier::EVENT_ENABLE, None)
857 .unwrap();
858 assert_eq!(
860 val,
861 PropertyValue::BitString {
862 unused_bits: 5,
863 data: vec![0b1110_0000],
864 }
865 );
866 }
867
868 #[test]
869 fn alert_enrollment_write_event_enable() {
870 let mut ae = AlertEnrollmentObject::new(1, "AE").unwrap();
871 ae.write_property(
872 PropertyIdentifier::EVENT_ENABLE,
873 None,
874 PropertyValue::BitString {
875 unused_bits: 5,
876 data: vec![0b1000_0000],
877 },
878 None,
879 )
880 .unwrap();
881 let val = ae
882 .read_property(PropertyIdentifier::EVENT_ENABLE, None)
883 .unwrap();
884 assert_eq!(
885 val,
886 PropertyValue::BitString {
887 unused_bits: 5,
888 data: vec![0b1000_0000],
889 }
890 );
891 }
892
893 #[test]
894 fn alert_enrollment_notification_class() {
895 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
896 let val = ae
897 .read_property(PropertyIdentifier::NOTIFICATION_CLASS, None)
898 .unwrap();
899 assert_eq!(val, PropertyValue::Unsigned(0));
900 }
901
902 #[test]
903 fn alert_enrollment_write_notification_class() {
904 let mut ae = AlertEnrollmentObject::new(1, "AE").unwrap();
905 ae.write_property(
906 PropertyIdentifier::NOTIFICATION_CLASS,
907 None,
908 PropertyValue::Unsigned(42),
909 None,
910 )
911 .unwrap();
912 let val = ae
913 .read_property(PropertyIdentifier::NOTIFICATION_CLASS, None)
914 .unwrap();
915 assert_eq!(val, PropertyValue::Unsigned(42));
916 }
917
918 #[test]
919 fn alert_enrollment_property_list() {
920 let ae = AlertEnrollmentObject::new(1, "AE").unwrap();
921 let props = ae.property_list();
922 assert!(props.contains(&PropertyIdentifier::PRESENT_VALUE));
923 assert!(props.contains(&PropertyIdentifier::EVENT_DETECTION_ENABLE));
924 assert!(props.contains(&PropertyIdentifier::EVENT_ENABLE));
925 assert!(props.contains(&PropertyIdentifier::NOTIFICATION_CLASS));
926 assert!(props.contains(&PropertyIdentifier::STATUS_FLAGS));
927 }
928}