1use 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 BinaryInputObject {
21 oid: ObjectIdentifier,
22 name: String,
23 description: String,
24 present_value: u32,
25 out_of_service: bool,
26 status_flags: StatusFlags,
27 polarity: u32,
29 reliability: u32,
31 active_text: String,
32 inactive_text: String,
33}
34
35impl BinaryInputObject {
36 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
37 let oid = ObjectIdentifier::new(ObjectType::BINARY_INPUT, instance)?;
38 Ok(Self {
39 oid,
40 name: name.into(),
41 description: String::new(),
42 present_value: 0,
43 out_of_service: false,
44 status_flags: StatusFlags::empty(),
45 polarity: 0,
46 reliability: 0,
47 active_text: "Active".into(),
48 inactive_text: "Inactive".into(),
49 })
50 }
51
52 pub fn set_present_value(&mut self, value: u32) {
54 self.present_value = value;
55 }
56
57 pub fn set_description(&mut self, desc: impl Into<String>) {
59 self.description = desc.into();
60 }
61}
62
63impl BACnetObject for BinaryInputObject {
64 fn object_identifier(&self) -> ObjectIdentifier {
65 self.oid
66 }
67
68 fn object_name(&self) -> &str {
69 &self.name
70 }
71
72 fn read_property(
73 &self,
74 property: PropertyIdentifier,
75 array_index: Option<u32>,
76 ) -> Result<PropertyValue, Error> {
77 if let Some(result) = read_common_properties!(self, property, array_index) {
78 return result;
79 }
80 match property {
81 p if p == PropertyIdentifier::OBJECT_TYPE => {
82 Ok(PropertyValue::Enumerated(ObjectType::BINARY_INPUT.to_raw()))
83 }
84 p if p == PropertyIdentifier::PRESENT_VALUE => {
85 Ok(PropertyValue::Enumerated(self.present_value))
86 }
87 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(0)),
88 p if p == PropertyIdentifier::POLARITY => Ok(PropertyValue::Enumerated(self.polarity)),
89 p if p == PropertyIdentifier::ACTIVE_TEXT => {
90 Ok(PropertyValue::CharacterString(self.active_text.clone()))
91 }
92 p if p == PropertyIdentifier::INACTIVE_TEXT => {
93 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
94 }
95 _ => Err(common::unknown_property_error()),
96 }
97 }
98
99 fn write_property(
100 &mut self,
101 property: PropertyIdentifier,
102 _array_index: Option<u32>,
103 value: PropertyValue,
104 _priority: Option<u8>,
105 ) -> Result<(), Error> {
106 if property == PropertyIdentifier::PRESENT_VALUE {
107 if !self.out_of_service {
108 return Err(common::write_access_denied_error());
109 }
110 if let PropertyValue::Enumerated(v) = value {
111 if v > 1 {
112 return Err(common::value_out_of_range_error());
113 }
114 self.present_value = v;
115 return Ok(());
116 }
117 return Err(common::invalid_data_type_error());
118 }
119 if property == PropertyIdentifier::ACTIVE_TEXT {
120 if let PropertyValue::CharacterString(s) = value {
121 self.active_text = s;
122 return Ok(());
123 }
124 return Err(common::invalid_data_type_error());
125 }
126 if property == PropertyIdentifier::INACTIVE_TEXT {
127 if let PropertyValue::CharacterString(s) = value {
128 self.inactive_text = s;
129 return Ok(());
130 }
131 return Err(common::invalid_data_type_error());
132 }
133 if let Some(result) =
134 common::write_out_of_service(&mut self.out_of_service, property, &value)
135 {
136 return result;
137 }
138 if let Some(result) = common::write_description(&mut self.description, property, &value) {
139 return result;
140 }
141 Err(common::write_access_denied_error())
142 }
143
144 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
145 static PROPS: &[PropertyIdentifier] = &[
146 PropertyIdentifier::OBJECT_IDENTIFIER,
147 PropertyIdentifier::OBJECT_NAME,
148 PropertyIdentifier::DESCRIPTION,
149 PropertyIdentifier::OBJECT_TYPE,
150 PropertyIdentifier::PRESENT_VALUE,
151 PropertyIdentifier::STATUS_FLAGS,
152 PropertyIdentifier::EVENT_STATE,
153 PropertyIdentifier::OUT_OF_SERVICE,
154 PropertyIdentifier::POLARITY,
155 PropertyIdentifier::RELIABILITY,
156 PropertyIdentifier::ACTIVE_TEXT,
157 PropertyIdentifier::INACTIVE_TEXT,
158 ];
159 Cow::Borrowed(PROPS)
160 }
161}
162
163pub struct BinaryOutputObject {
172 oid: ObjectIdentifier,
173 name: String,
174 description: String,
175 present_value: u32,
176 out_of_service: bool,
177 status_flags: StatusFlags,
178 priority_array: [Option<u32>; 16],
179 relinquish_default: u32,
180 polarity: u32,
182 reliability: u32,
184 active_text: String,
185 inactive_text: String,
186}
187
188impl BinaryOutputObject {
189 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
190 let oid = ObjectIdentifier::new(ObjectType::BINARY_OUTPUT, instance)?;
191 Ok(Self {
192 oid,
193 name: name.into(),
194 description: String::new(),
195 present_value: 0,
196 out_of_service: false,
197 status_flags: StatusFlags::empty(),
198 priority_array: [None; 16],
199 relinquish_default: 0,
200 polarity: 0,
201 reliability: 0,
202 active_text: "Active".into(),
203 inactive_text: "Inactive".into(),
204 })
205 }
206
207 pub fn set_description(&mut self, desc: impl Into<String>) {
209 self.description = desc.into();
210 }
211
212 fn recalculate_present_value(&mut self) {
213 self.present_value =
214 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
215 }
216}
217
218impl BACnetObject for BinaryOutputObject {
219 fn object_identifier(&self) -> ObjectIdentifier {
220 self.oid
221 }
222
223 fn object_name(&self) -> &str {
224 &self.name
225 }
226
227 fn read_property(
228 &self,
229 property: PropertyIdentifier,
230 array_index: Option<u32>,
231 ) -> Result<PropertyValue, Error> {
232 if let Some(result) = read_common_properties!(self, property, array_index) {
233 return result;
234 }
235 match property {
236 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
237 ObjectType::BINARY_OUTPUT.to_raw(),
238 )),
239 p if p == PropertyIdentifier::PRESENT_VALUE => {
240 Ok(PropertyValue::Enumerated(self.present_value))
241 }
242 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(0)),
243 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
244 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
245 }
246 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
247 Ok(PropertyValue::Enumerated(self.relinquish_default))
248 }
249 p if p == PropertyIdentifier::POLARITY => Ok(PropertyValue::Enumerated(self.polarity)),
250 p if p == PropertyIdentifier::ACTIVE_TEXT => {
251 Ok(PropertyValue::CharacterString(self.active_text.clone()))
252 }
253 p if p == PropertyIdentifier::INACTIVE_TEXT => {
254 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
255 }
256 _ => Err(common::unknown_property_error()),
257 }
258 }
259
260 fn write_property(
261 &mut self,
262 property: PropertyIdentifier,
263 array_index: Option<u32>,
264 value: PropertyValue,
265 priority: Option<u8>,
266 ) -> Result<(), Error> {
267 common::write_priority_array_direct!(self, property, array_index, value, |v| {
268 if let PropertyValue::Enumerated(e) = v {
269 if e > 1 {
270 Err(common::value_out_of_range_error())
271 } else {
272 Ok(e)
273 }
274 } else {
275 Err(common::invalid_data_type_error())
276 }
277 });
278 if property == PropertyIdentifier::PRESENT_VALUE {
279 return common::write_priority_array!(self, value, priority, |v| {
280 if let PropertyValue::Enumerated(e) = v {
281 if e > 1 {
282 Err(common::value_out_of_range_error())
283 } else {
284 Ok(e)
285 }
286 } else {
287 Err(common::invalid_data_type_error())
288 }
289 });
290 }
291 if property == PropertyIdentifier::ACTIVE_TEXT {
292 if let PropertyValue::CharacterString(s) = value {
293 self.active_text = s;
294 return Ok(());
295 }
296 return Err(common::invalid_data_type_error());
297 }
298 if property == PropertyIdentifier::INACTIVE_TEXT {
299 if let PropertyValue::CharacterString(s) = value {
300 self.inactive_text = s;
301 return Ok(());
302 }
303 return Err(common::invalid_data_type_error());
304 }
305 if let Some(result) =
306 common::write_out_of_service(&mut self.out_of_service, property, &value)
307 {
308 return result;
309 }
310 if let Some(result) = common::write_description(&mut self.description, property, &value) {
311 return result;
312 }
313 Err(common::write_access_denied_error())
314 }
315
316 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
317 static PROPS: &[PropertyIdentifier] = &[
318 PropertyIdentifier::OBJECT_IDENTIFIER,
319 PropertyIdentifier::OBJECT_NAME,
320 PropertyIdentifier::DESCRIPTION,
321 PropertyIdentifier::OBJECT_TYPE,
322 PropertyIdentifier::PRESENT_VALUE,
323 PropertyIdentifier::STATUS_FLAGS,
324 PropertyIdentifier::EVENT_STATE,
325 PropertyIdentifier::OUT_OF_SERVICE,
326 PropertyIdentifier::PRIORITY_ARRAY,
327 PropertyIdentifier::RELINQUISH_DEFAULT,
328 PropertyIdentifier::POLARITY,
329 PropertyIdentifier::RELIABILITY,
330 PropertyIdentifier::ACTIVE_TEXT,
331 PropertyIdentifier::INACTIVE_TEXT,
332 ];
333 Cow::Borrowed(PROPS)
334 }
335}
336
337pub struct BinaryValueObject {
346 oid: ObjectIdentifier,
347 name: String,
348 description: String,
349 present_value: u32, out_of_service: bool,
351 status_flags: StatusFlags,
352 priority_array: [Option<u32>; 16],
353 relinquish_default: u32,
354 reliability: u32,
356 active_text: String,
357 inactive_text: String,
358}
359
360impl BinaryValueObject {
361 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
363 let oid = ObjectIdentifier::new(ObjectType::BINARY_VALUE, instance)?;
364 Ok(Self {
365 oid,
366 name: name.into(),
367 description: String::new(),
368 present_value: 0, out_of_service: false,
370 status_flags: StatusFlags::empty(),
371 priority_array: [None; 16],
372 relinquish_default: 0,
373 reliability: 0,
374 active_text: "Active".into(),
375 inactive_text: "Inactive".into(),
376 })
377 }
378
379 pub fn set_description(&mut self, desc: impl Into<String>) {
381 self.description = desc.into();
382 }
383
384 fn recalculate_present_value(&mut self) {
385 self.present_value =
386 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
387 }
388}
389
390impl BACnetObject for BinaryValueObject {
391 fn object_identifier(&self) -> ObjectIdentifier {
392 self.oid
393 }
394
395 fn object_name(&self) -> &str {
396 &self.name
397 }
398
399 fn read_property(
400 &self,
401 property: PropertyIdentifier,
402 array_index: Option<u32>,
403 ) -> Result<PropertyValue, Error> {
404 if let Some(result) = read_common_properties!(self, property, array_index) {
405 return result;
406 }
407 match property {
408 p if p == PropertyIdentifier::OBJECT_TYPE => {
409 Ok(PropertyValue::Enumerated(ObjectType::BINARY_VALUE.to_raw()))
410 }
411 p if p == PropertyIdentifier::PRESENT_VALUE => {
412 Ok(PropertyValue::Enumerated(self.present_value))
413 }
414 p if p == PropertyIdentifier::EVENT_STATE => {
415 Ok(PropertyValue::Enumerated(0)) }
417 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
418 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
419 }
420 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
421 Ok(PropertyValue::Enumerated(self.relinquish_default))
422 }
423 p if p == PropertyIdentifier::ACTIVE_TEXT => {
424 Ok(PropertyValue::CharacterString(self.active_text.clone()))
425 }
426 p if p == PropertyIdentifier::INACTIVE_TEXT => {
427 Ok(PropertyValue::CharacterString(self.inactive_text.clone()))
428 }
429 _ => Err(common::unknown_property_error()),
430 }
431 }
432
433 fn write_property(
434 &mut self,
435 property: PropertyIdentifier,
436 array_index: Option<u32>,
437 value: PropertyValue,
438 priority: Option<u8>,
439 ) -> Result<(), Error> {
440 common::write_priority_array_direct!(self, property, array_index, value, |v| {
441 if let PropertyValue::Enumerated(e) = v {
442 if e > 1 {
443 Err(common::value_out_of_range_error())
444 } else {
445 Ok(e)
446 }
447 } else {
448 Err(common::invalid_data_type_error())
449 }
450 });
451 if property == PropertyIdentifier::PRESENT_VALUE {
452 return common::write_priority_array!(self, value, priority, |v| {
453 if let PropertyValue::Enumerated(e) = v {
454 if e > 1 {
455 Err(common::value_out_of_range_error())
456 } else {
457 Ok(e)
458 }
459 } else {
460 Err(common::invalid_data_type_error())
461 }
462 });
463 }
464 if property == PropertyIdentifier::ACTIVE_TEXT {
465 if let PropertyValue::CharacterString(s) = value {
466 self.active_text = s;
467 return Ok(());
468 }
469 return Err(common::invalid_data_type_error());
470 }
471 if property == PropertyIdentifier::INACTIVE_TEXT {
472 if let PropertyValue::CharacterString(s) = value {
473 self.inactive_text = s;
474 return Ok(());
475 }
476 return Err(common::invalid_data_type_error());
477 }
478 if let Some(result) =
479 common::write_out_of_service(&mut self.out_of_service, property, &value)
480 {
481 return result;
482 }
483 if let Some(result) = common::write_description(&mut self.description, property, &value) {
484 return result;
485 }
486 Err(common::write_access_denied_error())
487 }
488
489 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
490 static PROPS: &[PropertyIdentifier] = &[
491 PropertyIdentifier::OBJECT_IDENTIFIER,
492 PropertyIdentifier::OBJECT_NAME,
493 PropertyIdentifier::DESCRIPTION,
494 PropertyIdentifier::OBJECT_TYPE,
495 PropertyIdentifier::PRESENT_VALUE,
496 PropertyIdentifier::STATUS_FLAGS,
497 PropertyIdentifier::EVENT_STATE,
498 PropertyIdentifier::OUT_OF_SERVICE,
499 PropertyIdentifier::PRIORITY_ARRAY,
500 PropertyIdentifier::RELINQUISH_DEFAULT,
501 PropertyIdentifier::RELIABILITY,
502 PropertyIdentifier::ACTIVE_TEXT,
503 PropertyIdentifier::INACTIVE_TEXT,
504 ];
505 Cow::Borrowed(PROPS)
506 }
507}
508
509#[cfg(test)]
510mod tests {
511 use super::*;
512
513 #[test]
514 fn bv_read_present_value_default() {
515 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
516 let val = bv
517 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
518 .unwrap();
519 assert_eq!(val, PropertyValue::Enumerated(0)); }
521
522 #[test]
523 fn bv_write_present_value() {
524 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
525 bv.write_property(
526 PropertyIdentifier::PRESENT_VALUE,
527 None,
528 PropertyValue::Enumerated(1), Some(8),
530 )
531 .unwrap();
532 let val = bv
533 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
534 .unwrap();
535 assert_eq!(val, PropertyValue::Enumerated(1));
536 }
537
538 #[test]
539 fn bv_write_invalid_value_rejected() {
540 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
541 let result = bv.write_property(
542 PropertyIdentifier::PRESENT_VALUE,
543 None,
544 PropertyValue::Enumerated(2), Some(8),
546 );
547 assert!(result.is_err());
548 }
549
550 #[test]
551 fn bv_write_wrong_type_rejected() {
552 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
553 let result = bv.write_property(
554 PropertyIdentifier::PRESENT_VALUE,
555 None,
556 PropertyValue::Real(1.0), Some(8),
558 );
559 assert!(result.is_err());
560 }
561
562 #[test]
563 fn bv_read_object_type() {
564 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
565 let val = bv
566 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
567 .unwrap();
568 assert_eq!(
569 val,
570 PropertyValue::Enumerated(ObjectType::BINARY_VALUE.to_raw())
571 );
572 }
573
574 #[test]
575 fn bv_read_reliability_default() {
576 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
577 let val = bv
578 .read_property(PropertyIdentifier::RELIABILITY, None)
579 .unwrap();
580 assert_eq!(val, PropertyValue::Enumerated(0)); }
582
583 #[test]
586 fn bi_read_present_value_default() {
587 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
588 let val = bi
589 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
590 .unwrap();
591 assert_eq!(val, PropertyValue::Enumerated(0));
592 }
593
594 #[test]
595 fn bi_write_denied_when_in_service() {
596 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
597 let result = bi.write_property(
598 PropertyIdentifier::PRESENT_VALUE,
599 None,
600 PropertyValue::Enumerated(1),
601 None,
602 );
603 assert!(result.is_err());
604 }
605
606 #[test]
607 fn bi_write_allowed_when_out_of_service() {
608 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
609 bi.write_property(
610 PropertyIdentifier::OUT_OF_SERVICE,
611 None,
612 PropertyValue::Boolean(true),
613 None,
614 )
615 .unwrap();
616 bi.write_property(
617 PropertyIdentifier::PRESENT_VALUE,
618 None,
619 PropertyValue::Enumerated(1),
620 None,
621 )
622 .unwrap();
623 let val = bi
624 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
625 .unwrap();
626 assert_eq!(val, PropertyValue::Enumerated(1));
627 }
628
629 #[test]
630 fn bi_set_present_value() {
631 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
632 bi.set_present_value(1);
633 let val = bi
634 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
635 .unwrap();
636 assert_eq!(val, PropertyValue::Enumerated(1));
637 }
638
639 #[test]
640 fn bi_read_polarity_default() {
641 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
642 let val = bi
643 .read_property(PropertyIdentifier::POLARITY, None)
644 .unwrap();
645 assert_eq!(val, PropertyValue::Enumerated(0)); }
647
648 #[test]
649 fn bi_read_reliability_default() {
650 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
651 let val = bi
652 .read_property(PropertyIdentifier::RELIABILITY, None)
653 .unwrap();
654 assert_eq!(val, PropertyValue::Enumerated(0)); }
656
657 #[test]
660 fn bo_write_with_priority() {
661 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
662 bo.write_property(
663 PropertyIdentifier::PRESENT_VALUE,
664 None,
665 PropertyValue::Enumerated(1),
666 Some(8),
667 )
668 .unwrap();
669 let val = bo
670 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
671 .unwrap();
672 assert_eq!(val, PropertyValue::Enumerated(1));
673 let slot = bo
674 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
675 .unwrap();
676 assert_eq!(slot, PropertyValue::Enumerated(1));
677 }
678
679 #[test]
680 fn bo_relinquish_falls_to_default() {
681 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
682 bo.write_property(
683 PropertyIdentifier::PRESENT_VALUE,
684 None,
685 PropertyValue::Enumerated(1),
686 Some(16),
687 )
688 .unwrap();
689 assert_eq!(
690 bo.read_property(PropertyIdentifier::PRESENT_VALUE, None)
691 .unwrap(),
692 PropertyValue::Enumerated(1)
693 );
694 bo.write_property(
695 PropertyIdentifier::PRESENT_VALUE,
696 None,
697 PropertyValue::Null,
698 Some(16),
699 )
700 .unwrap();
701 assert_eq!(
702 bo.read_property(PropertyIdentifier::PRESENT_VALUE, None)
703 .unwrap(),
704 PropertyValue::Enumerated(0)
705 );
706 }
707
708 #[test]
709 fn bo_invalid_value_rejected() {
710 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
711 let result = bo.write_property(
712 PropertyIdentifier::PRESENT_VALUE,
713 None,
714 PropertyValue::Enumerated(2),
715 None,
716 );
717 assert!(result.is_err());
718 }
719
720 #[test]
721 fn bo_read_polarity_default() {
722 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
723 let val = bo
724 .read_property(PropertyIdentifier::POLARITY, None)
725 .unwrap();
726 assert_eq!(val, PropertyValue::Enumerated(0)); }
728
729 #[test]
730 fn bo_read_reliability_default() {
731 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
732 let val = bo
733 .read_property(PropertyIdentifier::RELIABILITY, None)
734 .unwrap();
735 assert_eq!(val, PropertyValue::Enumerated(0)); }
737
738 #[test]
741 fn bo_priority_array_index_zero_returns_size() {
742 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
743 let val = bo
744 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(0))
745 .unwrap();
746 assert_eq!(val, PropertyValue::Unsigned(16));
747 }
748
749 #[test]
750 fn bo_priority_array_index_out_of_bounds() {
751 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
752 let result = bo.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(17));
754 assert!(result.is_err());
755 }
756
757 #[test]
758 fn bo_priority_array_index_far_out_of_bounds() {
759 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
760 let result = bo.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(100));
761 assert!(result.is_err());
762 }
763
764 #[test]
767 fn bo_write_with_priority_zero_rejected() {
768 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
769 let result = bo.write_property(
771 PropertyIdentifier::PRESENT_VALUE,
772 None,
773 PropertyValue::Enumerated(1),
774 Some(0),
775 );
776 assert!(result.is_err());
777 }
778
779 #[test]
780 fn bo_write_with_priority_17_rejected() {
781 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
782 let result = bo.write_property(
784 PropertyIdentifier::PRESENT_VALUE,
785 None,
786 PropertyValue::Enumerated(1),
787 Some(17),
788 );
789 assert!(result.is_err());
790 }
791
792 #[test]
793 fn bo_write_with_priority_255_rejected() {
794 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
795 let result = bo.write_property(
797 PropertyIdentifier::PRESENT_VALUE,
798 None,
799 PropertyValue::Enumerated(1),
800 Some(255),
801 );
802 assert!(result.is_err());
803 }
804
805 #[test]
808 fn bi_polarity_is_readable_as_enumerated() {
809 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
810 let val = bi
811 .read_property(PropertyIdentifier::POLARITY, None)
812 .unwrap();
813 match val {
815 PropertyValue::Enumerated(v) => assert_eq!(v, 0),
816 other => panic!("Expected Enumerated for POLARITY, got {:?}", other),
817 }
818 }
819
820 #[test]
821 fn bi_reliability_is_readable_as_enumerated() {
822 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
823 let val = bi
824 .read_property(PropertyIdentifier::RELIABILITY, None)
825 .unwrap();
826 match val {
828 PropertyValue::Enumerated(v) => assert_eq!(v, 0),
829 other => panic!("Expected Enumerated for RELIABILITY, got {:?}", other),
830 }
831 }
832
833 #[test]
834 fn bo_polarity_is_readable_as_enumerated() {
835 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
836 let val = bo
837 .read_property(PropertyIdentifier::POLARITY, None)
838 .unwrap();
839 match val {
840 PropertyValue::Enumerated(v) => assert_eq!(v, 0),
841 other => panic!("Expected Enumerated for POLARITY, got {:?}", other),
842 }
843 }
844
845 #[test]
846 fn bo_reliability_is_readable_as_enumerated() {
847 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
848 let val = bo
849 .read_property(PropertyIdentifier::RELIABILITY, None)
850 .unwrap();
851 match val {
852 PropertyValue::Enumerated(v) => assert_eq!(v, 0),
853 other => panic!("Expected Enumerated for RELIABILITY, got {:?}", other),
854 }
855 }
856
857 #[test]
858 fn bi_polarity_in_property_list() {
859 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
860 let props = bi.property_list();
861 assert!(props.contains(&PropertyIdentifier::POLARITY));
862 assert!(props.contains(&PropertyIdentifier::RELIABILITY));
863 }
864
865 #[test]
866 fn bo_priority_array_read_all_slots_none_by_default() {
867 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
868 let val = bo
869 .read_property(PropertyIdentifier::PRIORITY_ARRAY, None)
870 .unwrap();
871 if let PropertyValue::List(elements) = val {
872 assert_eq!(elements.len(), 16);
873 for elem in &elements {
874 assert_eq!(elem, &PropertyValue::Null);
875 }
876 } else {
877 panic!("Expected List for priority array without index");
878 }
879 }
880
881 #[test]
884 fn bo_direct_priority_array_write_value() {
885 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
886 bo.write_property(
887 PropertyIdentifier::PRIORITY_ARRAY,
888 Some(5),
889 PropertyValue::Enumerated(1), None,
891 )
892 .unwrap();
893 assert_eq!(
894 bo.read_property(PropertyIdentifier::PRESENT_VALUE, None)
895 .unwrap(),
896 PropertyValue::Enumerated(1)
897 );
898 assert_eq!(
899 bo.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
900 .unwrap(),
901 PropertyValue::Enumerated(1)
902 );
903 }
904
905 #[test]
906 fn bo_direct_priority_array_relinquish() {
907 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
908 bo.write_property(
909 PropertyIdentifier::PRIORITY_ARRAY,
910 Some(5),
911 PropertyValue::Enumerated(1),
912 None,
913 )
914 .unwrap();
915 bo.write_property(
916 PropertyIdentifier::PRIORITY_ARRAY,
917 Some(5),
918 PropertyValue::Null,
919 None,
920 )
921 .unwrap();
922 assert_eq!(
924 bo.read_property(PropertyIdentifier::PRESENT_VALUE, None)
925 .unwrap(),
926 PropertyValue::Enumerated(0)
927 );
928 }
929
930 #[test]
931 fn bo_direct_priority_array_no_index_error() {
932 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
933 let result = bo.write_property(
934 PropertyIdentifier::PRIORITY_ARRAY,
935 None,
936 PropertyValue::Enumerated(1),
937 None,
938 );
939 assert!(result.is_err());
940 }
941
942 #[test]
943 fn bo_direct_priority_array_index_zero_error() {
944 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
945 let result = bo.write_property(
946 PropertyIdentifier::PRIORITY_ARRAY,
947 Some(0),
948 PropertyValue::Enumerated(1),
949 None,
950 );
951 assert!(result.is_err());
952 }
953
954 #[test]
955 fn bo_direct_priority_array_index_17_error() {
956 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
957 let result = bo.write_property(
958 PropertyIdentifier::PRIORITY_ARRAY,
959 Some(17),
960 PropertyValue::Enumerated(1),
961 None,
962 );
963 assert!(result.is_err());
964 }
965
966 #[test]
969 fn bv_write_with_priority() {
970 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
971 bv.write_property(
972 PropertyIdentifier::PRESENT_VALUE,
973 None,
974 PropertyValue::Enumerated(1),
975 Some(8),
976 )
977 .unwrap();
978 let val = bv
979 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
980 .unwrap();
981 assert_eq!(val, PropertyValue::Enumerated(1));
982 let slot = bv
983 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
984 .unwrap();
985 assert_eq!(slot, PropertyValue::Enumerated(1));
986 }
987
988 #[test]
989 fn bv_relinquish_falls_to_default() {
990 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
991 bv.write_property(
992 PropertyIdentifier::PRESENT_VALUE,
993 None,
994 PropertyValue::Enumerated(1),
995 Some(16),
996 )
997 .unwrap();
998 assert_eq!(
999 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1000 .unwrap(),
1001 PropertyValue::Enumerated(1)
1002 );
1003 bv.write_property(
1004 PropertyIdentifier::PRESENT_VALUE,
1005 None,
1006 PropertyValue::Null,
1007 Some(16),
1008 )
1009 .unwrap();
1010 assert_eq!(
1011 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1012 .unwrap(),
1013 PropertyValue::Enumerated(0) );
1015 }
1016
1017 #[test]
1018 fn bv_read_priority_array_all_none() {
1019 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1020 let val = bv
1021 .read_property(PropertyIdentifier::PRIORITY_ARRAY, None)
1022 .unwrap();
1023 if let PropertyValue::List(elements) = val {
1024 assert_eq!(elements.len(), 16);
1025 for elem in &elements {
1026 assert_eq!(elem, &PropertyValue::Null);
1027 }
1028 } else {
1029 panic!("Expected List for priority array without index");
1030 }
1031 }
1032
1033 #[test]
1034 fn bv_read_relinquish_default() {
1035 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1036 let val = bv
1037 .read_property(PropertyIdentifier::RELINQUISH_DEFAULT, None)
1038 .unwrap();
1039 assert_eq!(val, PropertyValue::Enumerated(0));
1040 }
1041
1042 #[test]
1043 fn bv_priority_array_in_property_list() {
1044 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1045 let props = bv.property_list();
1046 assert!(props.contains(&PropertyIdentifier::PRIORITY_ARRAY));
1047 assert!(props.contains(&PropertyIdentifier::RELINQUISH_DEFAULT));
1048 }
1049
1050 #[test]
1051 fn bv_direct_priority_array_write() {
1052 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1053 bv.write_property(
1054 PropertyIdentifier::PRIORITY_ARRAY,
1055 Some(5),
1056 PropertyValue::Enumerated(1),
1057 None,
1058 )
1059 .unwrap();
1060 assert_eq!(
1061 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1062 .unwrap(),
1063 PropertyValue::Enumerated(1)
1064 );
1065 assert_eq!(
1066 bv.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
1067 .unwrap(),
1068 PropertyValue::Enumerated(1)
1069 );
1070 }
1071
1072 #[test]
1073 fn bv_direct_priority_array_relinquish() {
1074 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1075 bv.write_property(
1076 PropertyIdentifier::PRIORITY_ARRAY,
1077 Some(5),
1078 PropertyValue::Enumerated(1),
1079 None,
1080 )
1081 .unwrap();
1082 bv.write_property(
1083 PropertyIdentifier::PRIORITY_ARRAY,
1084 Some(5),
1085 PropertyValue::Null,
1086 None,
1087 )
1088 .unwrap();
1089 assert_eq!(
1090 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1091 .unwrap(),
1092 PropertyValue::Enumerated(0) );
1094 }
1095
1096 #[test]
1099 fn bv_description_read_write() {
1100 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1101 assert_eq!(
1103 bv.read_property(PropertyIdentifier::DESCRIPTION, None)
1104 .unwrap(),
1105 PropertyValue::CharacterString(String::new())
1106 );
1107 bv.write_property(
1108 PropertyIdentifier::DESCRIPTION,
1109 None,
1110 PropertyValue::CharacterString("Occupied/Unoccupied".into()),
1111 None,
1112 )
1113 .unwrap();
1114 assert_eq!(
1115 bv.read_property(PropertyIdentifier::DESCRIPTION, None)
1116 .unwrap(),
1117 PropertyValue::CharacterString("Occupied/Unoccupied".into())
1118 );
1119 }
1120
1121 #[test]
1122 fn bv_description_in_property_list() {
1123 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1124 assert!(bv
1125 .property_list()
1126 .contains(&PropertyIdentifier::DESCRIPTION));
1127 }
1128
1129 #[test]
1130 fn bi_description_read_write() {
1131 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
1132 bi.write_property(
1133 PropertyIdentifier::DESCRIPTION,
1134 None,
1135 PropertyValue::CharacterString("Door contact".into()),
1136 None,
1137 )
1138 .unwrap();
1139 assert_eq!(
1140 bi.read_property(PropertyIdentifier::DESCRIPTION, None)
1141 .unwrap(),
1142 PropertyValue::CharacterString("Door contact".into())
1143 );
1144 }
1145
1146 #[test]
1147 fn bo_description_read_write() {
1148 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
1149 bo.write_property(
1150 PropertyIdentifier::DESCRIPTION,
1151 None,
1152 PropertyValue::CharacterString("Fan enable".into()),
1153 None,
1154 )
1155 .unwrap();
1156 assert_eq!(
1157 bo.read_property(PropertyIdentifier::DESCRIPTION, None)
1158 .unwrap(),
1159 PropertyValue::CharacterString("Fan enable".into())
1160 );
1161 }
1162
1163 #[test]
1164 fn bv_higher_priority_wins() {
1165 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1166 bv.write_property(
1168 PropertyIdentifier::PRESENT_VALUE,
1169 None,
1170 PropertyValue::Enumerated(0),
1171 Some(10),
1172 )
1173 .unwrap();
1174 bv.write_property(
1176 PropertyIdentifier::PRESENT_VALUE,
1177 None,
1178 PropertyValue::Enumerated(1),
1179 Some(5),
1180 )
1181 .unwrap();
1182 assert_eq!(
1183 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1184 .unwrap(),
1185 PropertyValue::Enumerated(1) );
1187 bv.write_property(
1189 PropertyIdentifier::PRESENT_VALUE,
1190 None,
1191 PropertyValue::Null,
1192 Some(5),
1193 )
1194 .unwrap();
1195 assert_eq!(
1196 bv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1197 .unwrap(),
1198 PropertyValue::Enumerated(0) );
1200 }
1201
1202 #[test]
1205 fn bi_active_inactive_text_defaults() {
1206 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
1207 assert_eq!(
1208 bi.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1209 .unwrap(),
1210 PropertyValue::CharacterString("Active".into())
1211 );
1212 assert_eq!(
1213 bi.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1214 .unwrap(),
1215 PropertyValue::CharacterString("Inactive".into())
1216 );
1217 }
1218
1219 #[test]
1220 fn bi_active_inactive_text_write_read() {
1221 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
1222 bi.write_property(
1223 PropertyIdentifier::ACTIVE_TEXT,
1224 None,
1225 PropertyValue::CharacterString("On".into()),
1226 None,
1227 )
1228 .unwrap();
1229 bi.write_property(
1230 PropertyIdentifier::INACTIVE_TEXT,
1231 None,
1232 PropertyValue::CharacterString("Off".into()),
1233 None,
1234 )
1235 .unwrap();
1236 assert_eq!(
1237 bi.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1238 .unwrap(),
1239 PropertyValue::CharacterString("On".into())
1240 );
1241 assert_eq!(
1242 bi.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1243 .unwrap(),
1244 PropertyValue::CharacterString("Off".into())
1245 );
1246 }
1247
1248 #[test]
1249 fn bi_active_text_wrong_type_rejected() {
1250 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
1251 assert!(bi
1252 .write_property(
1253 PropertyIdentifier::ACTIVE_TEXT,
1254 None,
1255 PropertyValue::Enumerated(1),
1256 None,
1257 )
1258 .is_err());
1259 }
1260
1261 #[test]
1262 fn bi_inactive_text_wrong_type_rejected() {
1263 let mut bi = BinaryInputObject::new(1, "BI-1").unwrap();
1264 assert!(bi
1265 .write_property(
1266 PropertyIdentifier::INACTIVE_TEXT,
1267 None,
1268 PropertyValue::Boolean(false),
1269 None,
1270 )
1271 .is_err());
1272 }
1273
1274 #[test]
1275 fn bi_active_inactive_text_in_property_list() {
1276 let bi = BinaryInputObject::new(1, "BI-1").unwrap();
1277 let props = bi.property_list();
1278 assert!(props.contains(&PropertyIdentifier::ACTIVE_TEXT));
1279 assert!(props.contains(&PropertyIdentifier::INACTIVE_TEXT));
1280 }
1281
1282 #[test]
1283 fn bo_active_inactive_text_defaults() {
1284 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
1285 assert_eq!(
1286 bo.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1287 .unwrap(),
1288 PropertyValue::CharacterString("Active".into())
1289 );
1290 assert_eq!(
1291 bo.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1292 .unwrap(),
1293 PropertyValue::CharacterString("Inactive".into())
1294 );
1295 }
1296
1297 #[test]
1298 fn bo_active_inactive_text_write_read() {
1299 let mut bo = BinaryOutputObject::new(1, "BO-1").unwrap();
1300 bo.write_property(
1301 PropertyIdentifier::ACTIVE_TEXT,
1302 None,
1303 PropertyValue::CharacterString("Running".into()),
1304 None,
1305 )
1306 .unwrap();
1307 bo.write_property(
1308 PropertyIdentifier::INACTIVE_TEXT,
1309 None,
1310 PropertyValue::CharacterString("Stopped".into()),
1311 None,
1312 )
1313 .unwrap();
1314 assert_eq!(
1315 bo.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1316 .unwrap(),
1317 PropertyValue::CharacterString("Running".into())
1318 );
1319 assert_eq!(
1320 bo.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1321 .unwrap(),
1322 PropertyValue::CharacterString("Stopped".into())
1323 );
1324 }
1325
1326 #[test]
1327 fn bo_active_inactive_text_in_property_list() {
1328 let bo = BinaryOutputObject::new(1, "BO-1").unwrap();
1329 let props = bo.property_list();
1330 assert!(props.contains(&PropertyIdentifier::ACTIVE_TEXT));
1331 assert!(props.contains(&PropertyIdentifier::INACTIVE_TEXT));
1332 }
1333
1334 #[test]
1335 fn bv_active_inactive_text_defaults() {
1336 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1337 assert_eq!(
1338 bv.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1339 .unwrap(),
1340 PropertyValue::CharacterString("Active".into())
1341 );
1342 assert_eq!(
1343 bv.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1344 .unwrap(),
1345 PropertyValue::CharacterString("Inactive".into())
1346 );
1347 }
1348
1349 #[test]
1350 fn bv_active_inactive_text_write_read() {
1351 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1352 bv.write_property(
1353 PropertyIdentifier::ACTIVE_TEXT,
1354 None,
1355 PropertyValue::CharacterString("Occupied".into()),
1356 None,
1357 )
1358 .unwrap();
1359 bv.write_property(
1360 PropertyIdentifier::INACTIVE_TEXT,
1361 None,
1362 PropertyValue::CharacterString("Unoccupied".into()),
1363 None,
1364 )
1365 .unwrap();
1366 assert_eq!(
1367 bv.read_property(PropertyIdentifier::ACTIVE_TEXT, None)
1368 .unwrap(),
1369 PropertyValue::CharacterString("Occupied".into())
1370 );
1371 assert_eq!(
1372 bv.read_property(PropertyIdentifier::INACTIVE_TEXT, None)
1373 .unwrap(),
1374 PropertyValue::CharacterString("Unoccupied".into())
1375 );
1376 }
1377
1378 #[test]
1379 fn bv_active_inactive_text_in_property_list() {
1380 let bv = BinaryValueObject::new(1, "BV-1").unwrap();
1381 let props = bv.property_list();
1382 assert!(props.contains(&PropertyIdentifier::ACTIVE_TEXT));
1383 assert!(props.contains(&PropertyIdentifier::INACTIVE_TEXT));
1384 }
1385
1386 #[test]
1387 fn bv_active_text_wrong_type_rejected() {
1388 let mut bv = BinaryValueObject::new(1, "BV-1").unwrap();
1389 assert!(bv
1390 .write_property(
1391 PropertyIdentifier::ACTIVE_TEXT,
1392 None,
1393 PropertyValue::Real(1.0),
1394 None,
1395 )
1396 .is_err());
1397 }
1398}