1use bacnet_types::enums::{ObjectType, PropertyIdentifier};
5use bacnet_types::error::Error;
6use bacnet_types::primitives::{BACnetTimeStamp, ObjectIdentifier, PropertyValue, StatusFlags};
7use std::borrow::Cow;
8
9use crate::common::{self, read_common_properties};
10use crate::event::{ChangeOfStateDetector, EventStateChange};
11use crate::traits::BACnetObject;
12
13pub struct MultiStateInputObject {
22 oid: ObjectIdentifier,
23 name: String,
24 description: String,
25 present_value: u32,
26 number_of_states: u32,
27 out_of_service: bool,
28 status_flags: StatusFlags,
29 reliability: u32,
31 state_text: Vec<String>,
32 alarm_values: Vec<u32>,
34 fault_values: Vec<u32>,
36 event_detector: ChangeOfStateDetector,
38}
39
40impl MultiStateInputObject {
41 pub fn new(
42 instance: u32,
43 name: impl Into<String>,
44 number_of_states: u32,
45 ) -> Result<Self, Error> {
46 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_INPUT, instance)?;
47 Ok(Self {
48 oid,
49 name: name.into(),
50 description: String::new(),
51 present_value: 1,
52 number_of_states,
53 out_of_service: false,
54 status_flags: StatusFlags::empty(),
55 reliability: 0,
56 state_text: (1..=number_of_states)
57 .map(|i| format!("State {i}"))
58 .collect(),
59 alarm_values: Vec::new(),
60 fault_values: Vec::new(),
61 event_detector: ChangeOfStateDetector::default(),
62 })
63 }
64
65 pub fn set_alarm_values(&mut self, values: Vec<u32>) {
67 self.alarm_values = values.clone();
68 self.event_detector.alarm_values = values;
69 }
70
71 pub fn set_fault_values(&mut self, values: Vec<u32>) {
73 self.fault_values = values;
74 }
75
76 pub fn set_present_value(&mut self, value: u32) {
78 self.present_value = value;
79 }
80
81 pub fn set_description(&mut self, desc: impl Into<String>) {
83 self.description = desc.into();
84 }
85}
86
87impl BACnetObject for MultiStateInputObject {
88 fn object_identifier(&self) -> ObjectIdentifier {
89 self.oid
90 }
91
92 fn object_name(&self) -> &str {
93 &self.name
94 }
95
96 fn supports_cov(&self) -> bool {
97 true
98 }
99
100 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
101 self.event_detector.evaluate(self.present_value)
102 }
103
104 fn read_property(
105 &self,
106 property: PropertyIdentifier,
107 array_index: Option<u32>,
108 ) -> Result<PropertyValue, Error> {
109 if property == PropertyIdentifier::STATUS_FLAGS {
110 return Ok(common::compute_status_flags(
111 self.status_flags,
112 self.reliability,
113 self.out_of_service,
114 self.event_detector.event_state.to_raw(),
115 ));
116 }
117 if let Some(result) = read_common_properties!(self, property, array_index) {
118 return result;
119 }
120 match property {
121 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
122 ObjectType::MULTI_STATE_INPUT.to_raw(),
123 )),
124 p if p == PropertyIdentifier::PRESENT_VALUE => {
125 Ok(PropertyValue::Unsigned(self.present_value as u64))
126 }
127 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
128 self.event_detector.event_state.to_raw(),
129 )),
130 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
131 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
132 }
133 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
134 None => Ok(PropertyValue::List(
135 self.state_text
136 .iter()
137 .map(|s| PropertyValue::CharacterString(s.clone()))
138 .collect(),
139 )),
140 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
141 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
142 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
143 ),
144 _ => Err(common::invalid_array_index_error()),
145 },
146 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
147 self.alarm_values
148 .iter()
149 .map(|v| PropertyValue::Unsigned(*v as u64))
150 .collect(),
151 )),
152 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
153 self.fault_values
154 .iter()
155 .map(|v| PropertyValue::Unsigned(*v as u64))
156 .collect(),
157 )),
158 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
159 unused_bits: 5,
160 data: vec![self.event_detector.event_enable << 5],
161 }),
162 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
163 unused_bits: 5,
164 data: vec![self.event_detector.acked_transitions << 5],
165 }),
166 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
167 self.event_detector.notification_class as u64,
168 )),
169 _ => Err(common::unknown_property_error()),
170 }
171 }
172
173 fn write_property(
174 &mut self,
175 property: PropertyIdentifier,
176 array_index: Option<u32>,
177 value: PropertyValue,
178 _priority: Option<u8>,
179 ) -> Result<(), Error> {
180 if property == PropertyIdentifier::PRESENT_VALUE {
181 if !self.out_of_service {
182 return Err(common::write_access_denied_error());
183 }
184 if let PropertyValue::Unsigned(v) = value {
185 if v < 1 || v > self.number_of_states as u64 {
186 return Err(common::value_out_of_range_error());
187 }
188 self.present_value = v as u32;
189 return Ok(());
190 }
191 return Err(common::invalid_data_type_error());
192 }
193 if property == PropertyIdentifier::STATE_TEXT {
194 match array_index {
195 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
196 if let PropertyValue::CharacterString(s) = value {
197 self.state_text[(idx - 1) as usize] = s;
198 return Ok(());
199 }
200 return Err(common::invalid_data_type_error());
201 }
202 None => return Err(common::write_access_denied_error()),
203 _ => return Err(common::invalid_array_index_error()),
204 }
205 }
206 if let Some(result) =
207 common::write_out_of_service(&mut self.out_of_service, property, &value)
208 {
209 return result;
210 }
211 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
212 return result;
213 }
214 if let Some(result) = common::write_description(&mut self.description, property, &value) {
215 return result;
216 }
217 Err(common::write_access_denied_error())
218 }
219
220 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
221 static PROPS: &[PropertyIdentifier] = &[
222 PropertyIdentifier::OBJECT_IDENTIFIER,
223 PropertyIdentifier::OBJECT_NAME,
224 PropertyIdentifier::DESCRIPTION,
225 PropertyIdentifier::OBJECT_TYPE,
226 PropertyIdentifier::PRESENT_VALUE,
227 PropertyIdentifier::STATUS_FLAGS,
228 PropertyIdentifier::EVENT_STATE,
229 PropertyIdentifier::OUT_OF_SERVICE,
230 PropertyIdentifier::NUMBER_OF_STATES,
231 PropertyIdentifier::RELIABILITY,
232 PropertyIdentifier::STATE_TEXT,
233 PropertyIdentifier::ALARM_VALUES,
234 PropertyIdentifier::FAULT_VALUES,
235 ];
236 Cow::Borrowed(PROPS)
237 }
238}
239
240pub struct MultiStateOutputObject {
249 oid: ObjectIdentifier,
250 name: String,
251 description: String,
252 present_value: u32,
253 number_of_states: u32,
254 out_of_service: bool,
255 status_flags: StatusFlags,
256 priority_array: [Option<u32>; 16],
257 relinquish_default: u32,
258 reliability: u32,
260 state_text: Vec<String>,
261 alarm_values: Vec<u32>,
262 fault_values: Vec<u32>,
263 event_detector: ChangeOfStateDetector,
265 value_source: common::ValueSourceTracking,
267}
268
269impl MultiStateOutputObject {
270 pub fn new(
271 instance: u32,
272 name: impl Into<String>,
273 number_of_states: u32,
274 ) -> Result<Self, Error> {
275 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_OUTPUT, instance)?;
276 Ok(Self {
277 oid,
278 name: name.into(),
279 description: String::new(),
280 present_value: 1,
281 number_of_states,
282 out_of_service: false,
283 status_flags: StatusFlags::empty(),
284 priority_array: [None; 16],
285 relinquish_default: 1,
286 reliability: 0,
287 state_text: (1..=number_of_states)
288 .map(|i| format!("State {i}"))
289 .collect(),
290 alarm_values: Vec::new(),
291 fault_values: Vec::new(),
292 event_detector: ChangeOfStateDetector::default(),
293 value_source: common::ValueSourceTracking::default(),
294 })
295 }
296
297 pub fn set_description(&mut self, desc: impl Into<String>) {
299 self.description = desc.into();
300 }
301
302 fn recalculate_present_value(&mut self) {
303 self.present_value =
304 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
305 }
306}
307
308impl BACnetObject for MultiStateOutputObject {
309 fn object_identifier(&self) -> ObjectIdentifier {
310 self.oid
311 }
312
313 fn object_name(&self) -> &str {
314 &self.name
315 }
316
317 fn supports_cov(&self) -> bool {
318 true
319 }
320
321 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
322 self.event_detector.evaluate(self.present_value)
323 }
324
325 fn read_property(
326 &self,
327 property: PropertyIdentifier,
328 array_index: Option<u32>,
329 ) -> Result<PropertyValue, Error> {
330 if property == PropertyIdentifier::STATUS_FLAGS {
331 return Ok(common::compute_status_flags(
332 self.status_flags,
333 self.reliability,
334 self.out_of_service,
335 self.event_detector.event_state.to_raw(),
336 ));
337 }
338 if let Some(result) = read_common_properties!(self, property, array_index) {
339 return result;
340 }
341 match property {
342 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
343 ObjectType::MULTI_STATE_OUTPUT.to_raw(),
344 )),
345 p if p == PropertyIdentifier::PRESENT_VALUE => {
346 Ok(PropertyValue::Unsigned(self.present_value as u64))
347 }
348 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
349 self.event_detector.event_state.to_raw(),
350 )),
351 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
352 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
353 }
354 p if p == PropertyIdentifier::VALUE_SOURCE => {
355 Ok(self.value_source.value_source.clone())
356 }
357 p if p == PropertyIdentifier::LAST_COMMAND_TIME => Ok(PropertyValue::Unsigned(
358 match self.value_source.last_command_time {
359 BACnetTimeStamp::SequenceNumber(n) => n,
360 _ => 0,
361 },
362 )),
363 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
364 common::read_priority_array!(self, array_index, |v: u32| PropertyValue::Unsigned(
365 v as u64
366 ))
367 }
368 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
369 Ok(PropertyValue::Unsigned(self.relinquish_default as u64))
370 }
371 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
372 Ok(common::current_command_priority(&self.priority_array))
373 }
374 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
375 None => Ok(PropertyValue::List(
376 self.state_text
377 .iter()
378 .map(|s| PropertyValue::CharacterString(s.clone()))
379 .collect(),
380 )),
381 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
382 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
383 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
384 ),
385 _ => Err(common::invalid_array_index_error()),
386 },
387 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
388 self.alarm_values
389 .iter()
390 .map(|v| PropertyValue::Unsigned(*v as u64))
391 .collect(),
392 )),
393 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
394 self.fault_values
395 .iter()
396 .map(|v| PropertyValue::Unsigned(*v as u64))
397 .collect(),
398 )),
399 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
400 unused_bits: 5,
401 data: vec![self.event_detector.event_enable << 5],
402 }),
403 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
404 unused_bits: 5,
405 data: vec![self.event_detector.acked_transitions << 5],
406 }),
407 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
408 self.event_detector.notification_class as u64,
409 )),
410 _ => Err(common::unknown_property_error()),
411 }
412 }
413
414 fn write_property(
415 &mut self,
416 property: PropertyIdentifier,
417 array_index: Option<u32>,
418 value: PropertyValue,
419 priority: Option<u8>,
420 ) -> Result<(), Error> {
421 {
422 let num_states = self.number_of_states;
423 common::write_priority_array_direct!(self, property, array_index, value, |v| {
424 if let PropertyValue::Unsigned(u) = v {
425 if u < 1 || u > num_states as u64 {
426 Err(common::value_out_of_range_error())
427 } else {
428 Ok(u as u32)
429 }
430 } else {
431 Err(common::invalid_data_type_error())
432 }
433 });
434 }
435 if property == PropertyIdentifier::PRESENT_VALUE {
436 let num_states = self.number_of_states;
437 return common::write_priority_array!(self, value, priority, |v| {
438 if let PropertyValue::Unsigned(u) = v {
439 if u < 1 || u > num_states as u64 {
440 Err(common::value_out_of_range_error())
441 } else {
442 Ok(u as u32)
443 }
444 } else {
445 Err(common::invalid_data_type_error())
446 }
447 });
448 }
449 if property == PropertyIdentifier::STATE_TEXT {
450 match array_index {
451 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
452 if let PropertyValue::CharacterString(s) = value {
453 self.state_text[(idx - 1) as usize] = s;
454 return Ok(());
455 }
456 return Err(common::invalid_data_type_error());
457 }
458 None => return Err(common::write_access_denied_error()),
459 _ => return Err(common::invalid_array_index_error()),
460 }
461 }
462 if let Some(result) =
463 common::write_out_of_service(&mut self.out_of_service, property, &value)
464 {
465 return result;
466 }
467 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
468 return result;
469 }
470 if let Some(result) = common::write_description(&mut self.description, property, &value) {
471 return result;
472 }
473 Err(common::write_access_denied_error())
474 }
475
476 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
477 static PROPS: &[PropertyIdentifier] = &[
478 PropertyIdentifier::OBJECT_IDENTIFIER,
479 PropertyIdentifier::OBJECT_NAME,
480 PropertyIdentifier::DESCRIPTION,
481 PropertyIdentifier::OBJECT_TYPE,
482 PropertyIdentifier::PRESENT_VALUE,
483 PropertyIdentifier::STATUS_FLAGS,
484 PropertyIdentifier::EVENT_STATE,
485 PropertyIdentifier::OUT_OF_SERVICE,
486 PropertyIdentifier::NUMBER_OF_STATES,
487 PropertyIdentifier::PRIORITY_ARRAY,
488 PropertyIdentifier::RELINQUISH_DEFAULT,
489 PropertyIdentifier::CURRENT_COMMAND_PRIORITY,
490 PropertyIdentifier::RELIABILITY,
491 PropertyIdentifier::STATE_TEXT,
492 PropertyIdentifier::ALARM_VALUES,
493 PropertyIdentifier::FAULT_VALUES,
494 ];
495 Cow::Borrowed(PROPS)
496 }
497}
498
499pub struct MultiStateValueObject {
508 oid: ObjectIdentifier,
509 name: String,
510 description: String,
511 present_value: u32,
512 number_of_states: u32,
513 out_of_service: bool,
514 status_flags: StatusFlags,
515 priority_array: [Option<u32>; 16],
516 relinquish_default: u32,
517 reliability: u32,
519 state_text: Vec<String>,
520 alarm_values: Vec<u32>,
521 fault_values: Vec<u32>,
522 event_detector: ChangeOfStateDetector,
524 value_source: common::ValueSourceTracking,
526}
527
528impl MultiStateValueObject {
529 pub fn new(
530 instance: u32,
531 name: impl Into<String>,
532 number_of_states: u32,
533 ) -> Result<Self, Error> {
534 let oid = ObjectIdentifier::new(ObjectType::MULTI_STATE_VALUE, instance)?;
535 Ok(Self {
536 oid,
537 name: name.into(),
538 description: String::new(),
539 present_value: 1,
540 number_of_states,
541 out_of_service: false,
542 status_flags: StatusFlags::empty(),
543 priority_array: [None; 16],
544 relinquish_default: 1,
545 reliability: 0,
546 state_text: (1..=number_of_states)
547 .map(|i| format!("State {i}"))
548 .collect(),
549 alarm_values: Vec::new(),
550 fault_values: Vec::new(),
551 event_detector: ChangeOfStateDetector::default(),
552 value_source: common::ValueSourceTracking::default(),
553 })
554 }
555
556 pub fn set_description(&mut self, desc: impl Into<String>) {
558 self.description = desc.into();
559 }
560
561 fn recalculate_present_value(&mut self) {
562 self.present_value =
563 common::recalculate_from_priority_array(&self.priority_array, self.relinquish_default);
564 }
565}
566
567impl BACnetObject for MultiStateValueObject {
568 fn object_identifier(&self) -> ObjectIdentifier {
569 self.oid
570 }
571
572 fn object_name(&self) -> &str {
573 &self.name
574 }
575
576 fn supports_cov(&self) -> bool {
577 true
578 }
579
580 fn evaluate_intrinsic_reporting(&mut self) -> Option<EventStateChange> {
581 self.event_detector.evaluate(self.present_value)
582 }
583
584 fn read_property(
585 &self,
586 property: PropertyIdentifier,
587 array_index: Option<u32>,
588 ) -> Result<PropertyValue, Error> {
589 if property == PropertyIdentifier::STATUS_FLAGS {
590 return Ok(common::compute_status_flags(
591 self.status_flags,
592 self.reliability,
593 self.out_of_service,
594 self.event_detector.event_state.to_raw(),
595 ));
596 }
597 if let Some(result) = read_common_properties!(self, property, array_index) {
598 return result;
599 }
600 match property {
601 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
602 ObjectType::MULTI_STATE_VALUE.to_raw(),
603 )),
604 p if p == PropertyIdentifier::PRESENT_VALUE => {
605 Ok(PropertyValue::Unsigned(self.present_value as u64))
606 }
607 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
608 self.event_detector.event_state.to_raw(),
609 )),
610 p if p == PropertyIdentifier::NUMBER_OF_STATES => {
611 Ok(PropertyValue::Unsigned(self.number_of_states as u64))
612 }
613 p if p == PropertyIdentifier::VALUE_SOURCE => {
614 Ok(self.value_source.value_source.clone())
615 }
616 p if p == PropertyIdentifier::LAST_COMMAND_TIME => Ok(PropertyValue::Unsigned(
617 match self.value_source.last_command_time {
618 BACnetTimeStamp::SequenceNumber(n) => n,
619 _ => 0,
620 },
621 )),
622 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
623 common::read_priority_array!(self, array_index, |v: u32| PropertyValue::Unsigned(
624 v as u64
625 ))
626 }
627 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
628 Ok(PropertyValue::Unsigned(self.relinquish_default as u64))
629 }
630 p if p == PropertyIdentifier::CURRENT_COMMAND_PRIORITY => {
631 Ok(common::current_command_priority(&self.priority_array))
632 }
633 p if p == PropertyIdentifier::STATE_TEXT => match array_index {
634 None => Ok(PropertyValue::List(
635 self.state_text
636 .iter()
637 .map(|s| PropertyValue::CharacterString(s.clone()))
638 .collect(),
639 )),
640 Some(0) => Ok(PropertyValue::Unsigned(self.state_text.len() as u64)),
641 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => Ok(
642 PropertyValue::CharacterString(self.state_text[(idx - 1) as usize].clone()),
643 ),
644 _ => Err(common::invalid_array_index_error()),
645 },
646 p if p == PropertyIdentifier::ALARM_VALUES => Ok(PropertyValue::List(
647 self.alarm_values
648 .iter()
649 .map(|v| PropertyValue::Unsigned(*v as u64))
650 .collect(),
651 )),
652 p if p == PropertyIdentifier::FAULT_VALUES => Ok(PropertyValue::List(
653 self.fault_values
654 .iter()
655 .map(|v| PropertyValue::Unsigned(*v as u64))
656 .collect(),
657 )),
658 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
659 unused_bits: 5,
660 data: vec![self.event_detector.event_enable << 5],
661 }),
662 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
663 unused_bits: 5,
664 data: vec![self.event_detector.acked_transitions << 5],
665 }),
666 p if p == PropertyIdentifier::NOTIFICATION_CLASS => Ok(PropertyValue::Unsigned(
667 self.event_detector.notification_class as u64,
668 )),
669 _ => Err(common::unknown_property_error()),
670 }
671 }
672
673 fn write_property(
674 &mut self,
675 property: PropertyIdentifier,
676 array_index: Option<u32>,
677 value: PropertyValue,
678 priority: Option<u8>,
679 ) -> Result<(), Error> {
680 {
681 let num_states = self.number_of_states;
682 common::write_priority_array_direct!(self, property, array_index, value, |v| {
683 if let PropertyValue::Unsigned(u) = v {
684 if u < 1 || u > num_states as u64 {
685 Err(common::value_out_of_range_error())
686 } else {
687 Ok(u as u32)
688 }
689 } else {
690 Err(common::invalid_data_type_error())
691 }
692 });
693 }
694 if property == PropertyIdentifier::PRESENT_VALUE {
695 let num_states = self.number_of_states;
696 return common::write_priority_array!(self, value, priority, |v| {
697 if let PropertyValue::Unsigned(u) = v {
698 if u < 1 || u > num_states as u64 {
699 Err(common::value_out_of_range_error())
700 } else {
701 Ok(u as u32)
702 }
703 } else {
704 Err(common::invalid_data_type_error())
705 }
706 });
707 }
708 if property == PropertyIdentifier::STATE_TEXT {
709 match array_index {
710 Some(idx) if idx >= 1 && (idx as usize) <= self.state_text.len() => {
711 if let PropertyValue::CharacterString(s) = value {
712 self.state_text[(idx - 1) as usize] = s;
713 return Ok(());
714 }
715 return Err(common::invalid_data_type_error());
716 }
717 None => return Err(common::write_access_denied_error()),
718 _ => return Err(common::invalid_array_index_error()),
719 }
720 }
721 if let Some(result) =
722 common::write_out_of_service(&mut self.out_of_service, property, &value)
723 {
724 return result;
725 }
726 if let Some(result) = common::write_object_name(&mut self.name, property, &value) {
727 return result;
728 }
729 if let Some(result) = common::write_description(&mut self.description, property, &value) {
730 return result;
731 }
732 Err(common::write_access_denied_error())
733 }
734
735 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
736 static PROPS: &[PropertyIdentifier] = &[
737 PropertyIdentifier::OBJECT_IDENTIFIER,
738 PropertyIdentifier::OBJECT_NAME,
739 PropertyIdentifier::DESCRIPTION,
740 PropertyIdentifier::OBJECT_TYPE,
741 PropertyIdentifier::PRESENT_VALUE,
742 PropertyIdentifier::STATUS_FLAGS,
743 PropertyIdentifier::EVENT_STATE,
744 PropertyIdentifier::OUT_OF_SERVICE,
745 PropertyIdentifier::NUMBER_OF_STATES,
746 PropertyIdentifier::PRIORITY_ARRAY,
747 PropertyIdentifier::RELINQUISH_DEFAULT,
748 PropertyIdentifier::CURRENT_COMMAND_PRIORITY,
749 PropertyIdentifier::RELIABILITY,
750 PropertyIdentifier::STATE_TEXT,
751 ];
752 Cow::Borrowed(PROPS)
753 }
754}
755
756#[cfg(test)]
757mod tests {
758 use super::*;
759
760 #[test]
763 fn msi_read_present_value_default() {
764 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
765 let val = msi
766 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
767 .unwrap();
768 assert_eq!(val, PropertyValue::Unsigned(1));
769 }
770
771 #[test]
772 fn msi_read_number_of_states() {
773 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
774 let val = msi
775 .read_property(PropertyIdentifier::NUMBER_OF_STATES, None)
776 .unwrap();
777 assert_eq!(val, PropertyValue::Unsigned(4));
778 }
779
780 #[test]
781 fn msi_write_denied_when_in_service() {
782 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
783 let result = msi.write_property(
784 PropertyIdentifier::PRESENT_VALUE,
785 None,
786 PropertyValue::Unsigned(2),
787 None,
788 );
789 assert!(result.is_err());
790 }
791
792 #[test]
793 fn msi_write_allowed_when_out_of_service() {
794 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
795 msi.write_property(
796 PropertyIdentifier::OUT_OF_SERVICE,
797 None,
798 PropertyValue::Boolean(true),
799 None,
800 )
801 .unwrap();
802 msi.write_property(
803 PropertyIdentifier::PRESENT_VALUE,
804 None,
805 PropertyValue::Unsigned(3),
806 None,
807 )
808 .unwrap();
809 let val = msi
810 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
811 .unwrap();
812 assert_eq!(val, PropertyValue::Unsigned(3));
813 }
814
815 #[test]
816 fn msi_write_out_of_range_rejected() {
817 let mut msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
818 msi.write_property(
819 PropertyIdentifier::OUT_OF_SERVICE,
820 None,
821 PropertyValue::Boolean(true),
822 None,
823 )
824 .unwrap();
825 assert!(msi
826 .write_property(
827 PropertyIdentifier::PRESENT_VALUE,
828 None,
829 PropertyValue::Unsigned(0),
830 None
831 )
832 .is_err());
833 assert!(msi
834 .write_property(
835 PropertyIdentifier::PRESENT_VALUE,
836 None,
837 PropertyValue::Unsigned(5),
838 None
839 )
840 .is_err());
841 }
842
843 #[test]
844 fn msi_read_reliability_default() {
845 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
846 let val = msi
847 .read_property(PropertyIdentifier::RELIABILITY, None)
848 .unwrap();
849 assert_eq!(val, PropertyValue::Enumerated(0)); }
851
852 #[test]
855 fn mso_write_with_priority() {
856 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
857 mso.write_property(
858 PropertyIdentifier::PRESENT_VALUE,
859 None,
860 PropertyValue::Unsigned(3),
861 Some(8),
862 )
863 .unwrap();
864 let val = mso
865 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
866 .unwrap();
867 assert_eq!(val, PropertyValue::Unsigned(3));
868 let slot = mso
869 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
870 .unwrap();
871 assert_eq!(slot, PropertyValue::Unsigned(3));
872 }
873
874 #[test]
875 fn mso_relinquish_falls_to_default() {
876 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
877 mso.write_property(
878 PropertyIdentifier::PRESENT_VALUE,
879 None,
880 PropertyValue::Unsigned(4),
881 Some(16),
882 )
883 .unwrap();
884 assert_eq!(
885 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
886 .unwrap(),
887 PropertyValue::Unsigned(4)
888 );
889 mso.write_property(
890 PropertyIdentifier::PRESENT_VALUE,
891 None,
892 PropertyValue::Null,
893 Some(16),
894 )
895 .unwrap();
896 assert_eq!(
897 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
898 .unwrap(),
899 PropertyValue::Unsigned(1)
900 ); }
902
903 #[test]
904 fn mso_out_of_range_rejected() {
905 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
906 assert!(mso
907 .write_property(
908 PropertyIdentifier::PRESENT_VALUE,
909 None,
910 PropertyValue::Unsigned(0),
911 None
912 )
913 .is_err());
914 assert!(mso
915 .write_property(
916 PropertyIdentifier::PRESENT_VALUE,
917 None,
918 PropertyValue::Unsigned(6),
919 None
920 )
921 .is_err());
922 }
923
924 #[test]
925 fn mso_read_reliability_default() {
926 let mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
927 let val = mso
928 .read_property(PropertyIdentifier::RELIABILITY, None)
929 .unwrap();
930 assert_eq!(val, PropertyValue::Enumerated(0)); }
932
933 #[test]
936 fn msv_read_present_value_default() {
937 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
938 let val = msv
939 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
940 .unwrap();
941 assert_eq!(val, PropertyValue::Unsigned(1));
942 }
943
944 #[test]
945 fn msv_write_with_priority() {
946 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
947 msv.write_property(
948 PropertyIdentifier::PRESENT_VALUE,
949 None,
950 PropertyValue::Unsigned(2),
951 Some(8),
952 )
953 .unwrap();
954 let val = msv
955 .read_property(PropertyIdentifier::PRESENT_VALUE, None)
956 .unwrap();
957 assert_eq!(val, PropertyValue::Unsigned(2));
958 let slot = msv
959 .read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(8))
960 .unwrap();
961 assert_eq!(slot, PropertyValue::Unsigned(2));
962 }
963
964 #[test]
965 fn msv_relinquish_falls_to_default() {
966 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
967 msv.write_property(
968 PropertyIdentifier::PRESENT_VALUE,
969 None,
970 PropertyValue::Unsigned(3),
971 Some(16),
972 )
973 .unwrap();
974 assert_eq!(
975 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
976 .unwrap(),
977 PropertyValue::Unsigned(3)
978 );
979 msv.write_property(
980 PropertyIdentifier::PRESENT_VALUE,
981 None,
982 PropertyValue::Null,
983 Some(16),
984 )
985 .unwrap();
986 assert_eq!(
987 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
988 .unwrap(),
989 PropertyValue::Unsigned(1)
990 ); }
992
993 #[test]
994 fn msv_read_priority_array_all_none() {
995 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
996 let val = msv
997 .read_property(PropertyIdentifier::PRIORITY_ARRAY, None)
998 .unwrap();
999 if let PropertyValue::List(elements) = val {
1000 assert_eq!(elements.len(), 16);
1001 for elem in &elements {
1002 assert_eq!(elem, &PropertyValue::Null);
1003 }
1004 } else {
1005 panic!("Expected List for priority array without index");
1006 }
1007 }
1008
1009 #[test]
1010 fn msv_read_relinquish_default() {
1011 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1012 let val = msv
1013 .read_property(PropertyIdentifier::RELINQUISH_DEFAULT, None)
1014 .unwrap();
1015 assert_eq!(val, PropertyValue::Unsigned(1));
1016 }
1017
1018 #[test]
1019 fn msv_write_out_of_range_rejected() {
1020 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1021 assert!(msv
1022 .write_property(
1023 PropertyIdentifier::PRESENT_VALUE,
1024 None,
1025 PropertyValue::Unsigned(0),
1026 None
1027 )
1028 .is_err());
1029 assert!(msv
1030 .write_property(
1031 PropertyIdentifier::PRESENT_VALUE,
1032 None,
1033 PropertyValue::Unsigned(4),
1034 None
1035 )
1036 .is_err());
1037 }
1038
1039 #[test]
1040 fn msv_write_wrong_type_rejected() {
1041 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1042 let result = msv.write_property(
1043 PropertyIdentifier::PRESENT_VALUE,
1044 None,
1045 PropertyValue::Real(1.0),
1046 None,
1047 );
1048 assert!(result.is_err());
1049 }
1050
1051 #[test]
1052 fn msv_read_object_type() {
1053 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1054 let val = msv
1055 .read_property(PropertyIdentifier::OBJECT_TYPE, None)
1056 .unwrap();
1057 assert_eq!(
1058 val,
1059 PropertyValue::Enumerated(ObjectType::MULTI_STATE_VALUE.to_raw())
1060 );
1061 }
1062
1063 #[test]
1064 fn msv_read_reliability_default() {
1065 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1066 let val = msv
1067 .read_property(PropertyIdentifier::RELIABILITY, None)
1068 .unwrap();
1069 assert_eq!(val, PropertyValue::Enumerated(0)); }
1071
1072 #[test]
1075 fn msv_direct_priority_array_write_value() {
1076 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1077 msv.write_property(
1078 PropertyIdentifier::PRIORITY_ARRAY,
1079 Some(5),
1080 PropertyValue::Unsigned(3),
1081 None,
1082 )
1083 .unwrap();
1084 assert_eq!(
1085 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1086 .unwrap(),
1087 PropertyValue::Unsigned(3)
1088 );
1089 assert_eq!(
1090 msv.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
1091 .unwrap(),
1092 PropertyValue::Unsigned(3)
1093 );
1094 }
1095
1096 #[test]
1097 fn msv_direct_priority_array_relinquish() {
1098 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1099 msv.write_property(
1100 PropertyIdentifier::PRIORITY_ARRAY,
1101 Some(5),
1102 PropertyValue::Unsigned(3),
1103 None,
1104 )
1105 .unwrap();
1106 msv.write_property(
1107 PropertyIdentifier::PRIORITY_ARRAY,
1108 Some(5),
1109 PropertyValue::Null,
1110 None,
1111 )
1112 .unwrap();
1113 assert_eq!(
1114 msv.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1115 .unwrap(),
1116 PropertyValue::Unsigned(1)
1117 ); }
1119
1120 #[test]
1121 fn msv_direct_priority_array_no_index_error() {
1122 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1123 let result = msv.write_property(
1124 PropertyIdentifier::PRIORITY_ARRAY,
1125 None,
1126 PropertyValue::Unsigned(3),
1127 None,
1128 );
1129 assert!(result.is_err());
1130 }
1131
1132 #[test]
1133 fn msv_direct_priority_array_index_zero_error() {
1134 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1135 let result = msv.write_property(
1136 PropertyIdentifier::PRIORITY_ARRAY,
1137 Some(0),
1138 PropertyValue::Unsigned(3),
1139 None,
1140 );
1141 assert!(result.is_err());
1142 }
1143
1144 #[test]
1145 fn msv_direct_priority_array_index_17_error() {
1146 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1147 let result = msv.write_property(
1148 PropertyIdentifier::PRIORITY_ARRAY,
1149 Some(17),
1150 PropertyValue::Unsigned(3),
1151 None,
1152 );
1153 assert!(result.is_err());
1154 }
1155
1156 #[test]
1157 fn msv_direct_priority_array_range_validation() {
1158 let mut msv = MultiStateValueObject::new(1, "MSV-1", 5).unwrap();
1159 assert!(msv
1161 .write_property(
1162 PropertyIdentifier::PRIORITY_ARRAY,
1163 Some(1),
1164 PropertyValue::Unsigned(0),
1165 None
1166 )
1167 .is_err());
1168 assert!(msv
1170 .write_property(
1171 PropertyIdentifier::PRIORITY_ARRAY,
1172 Some(1),
1173 PropertyValue::Unsigned(6),
1174 None
1175 )
1176 .is_err());
1177 msv.write_property(
1179 PropertyIdentifier::PRIORITY_ARRAY,
1180 Some(1),
1181 PropertyValue::Unsigned(5),
1182 None,
1183 )
1184 .unwrap();
1185 }
1186
1187 #[test]
1190 fn mso_direct_priority_array_write_value() {
1191 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1192 mso.write_property(
1193 PropertyIdentifier::PRIORITY_ARRAY,
1194 Some(5),
1195 PropertyValue::Unsigned(3),
1196 None,
1197 )
1198 .unwrap();
1199 assert_eq!(
1200 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1201 .unwrap(),
1202 PropertyValue::Unsigned(3)
1203 );
1204 assert_eq!(
1205 mso.read_property(PropertyIdentifier::PRIORITY_ARRAY, Some(5))
1206 .unwrap(),
1207 PropertyValue::Unsigned(3)
1208 );
1209 }
1210
1211 #[test]
1212 fn mso_direct_priority_array_relinquish() {
1213 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1214 mso.write_property(
1215 PropertyIdentifier::PRIORITY_ARRAY,
1216 Some(5),
1217 PropertyValue::Unsigned(3),
1218 None,
1219 )
1220 .unwrap();
1221 mso.write_property(
1222 PropertyIdentifier::PRIORITY_ARRAY,
1223 Some(5),
1224 PropertyValue::Null,
1225 None,
1226 )
1227 .unwrap();
1228 assert_eq!(
1230 mso.read_property(PropertyIdentifier::PRESENT_VALUE, None)
1231 .unwrap(),
1232 PropertyValue::Unsigned(1)
1233 );
1234 }
1235
1236 #[test]
1237 fn mso_direct_priority_array_no_index_error() {
1238 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1239 let result = mso.write_property(
1240 PropertyIdentifier::PRIORITY_ARRAY,
1241 None,
1242 PropertyValue::Unsigned(3),
1243 None,
1244 );
1245 assert!(result.is_err());
1246 }
1247
1248 #[test]
1249 fn mso_direct_priority_array_index_zero_error() {
1250 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1251 let result = mso.write_property(
1252 PropertyIdentifier::PRIORITY_ARRAY,
1253 Some(0),
1254 PropertyValue::Unsigned(3),
1255 None,
1256 );
1257 assert!(result.is_err());
1258 }
1259
1260 #[test]
1261 fn mso_direct_priority_array_index_17_error() {
1262 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1263 let result = mso.write_property(
1264 PropertyIdentifier::PRIORITY_ARRAY,
1265 Some(17),
1266 PropertyValue::Unsigned(3),
1267 None,
1268 );
1269 assert!(result.is_err());
1270 }
1271
1272 #[test]
1275 fn msi_state_text_defaults() {
1276 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1277 let val = msi
1278 .read_property(PropertyIdentifier::STATE_TEXT, None)
1279 .unwrap();
1280 assert_eq!(
1281 val,
1282 PropertyValue::List(vec![
1283 PropertyValue::CharacterString("State 1".into()),
1284 PropertyValue::CharacterString("State 2".into()),
1285 PropertyValue::CharacterString("State 3".into()),
1286 ])
1287 );
1288 }
1289
1290 #[test]
1291 fn msi_state_text_index_zero_returns_length() {
1292 let msi = MultiStateInputObject::new(1, "MSI-1", 4).unwrap();
1293 let val = msi
1294 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1295 .unwrap();
1296 assert_eq!(val, PropertyValue::Unsigned(4));
1297 }
1298
1299 #[test]
1300 fn msi_state_text_valid_index() {
1301 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1302 let val = msi
1303 .read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1304 .unwrap();
1305 assert_eq!(val, PropertyValue::CharacterString("State 2".into()));
1306 }
1307
1308 #[test]
1309 fn msi_state_text_invalid_index_error() {
1310 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1311 assert!(msi
1312 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1313 .is_err());
1314 assert!(msi
1315 .read_property(PropertyIdentifier::STATE_TEXT, Some(100))
1316 .is_err());
1317 }
1318
1319 #[test]
1320 fn msi_state_text_write_at_index() {
1321 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1322 msi.write_property(
1323 PropertyIdentifier::STATE_TEXT,
1324 Some(2),
1325 PropertyValue::CharacterString("Occupied".into()),
1326 None,
1327 )
1328 .unwrap();
1329 let val = msi
1330 .read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1331 .unwrap();
1332 assert_eq!(val, PropertyValue::CharacterString("Occupied".into()));
1333 }
1334
1335 #[test]
1336 fn msi_state_text_write_wrong_type_rejected() {
1337 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1338 assert!(msi
1339 .write_property(
1340 PropertyIdentifier::STATE_TEXT,
1341 Some(1),
1342 PropertyValue::Unsigned(42),
1343 None,
1344 )
1345 .is_err());
1346 }
1347
1348 #[test]
1349 fn msi_state_text_write_bad_index_rejected() {
1350 let mut msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1351 assert!(msi
1353 .write_property(
1354 PropertyIdentifier::STATE_TEXT,
1355 Some(0),
1356 PropertyValue::CharacterString("X".into()),
1357 None,
1358 )
1359 .is_err());
1360 assert!(msi
1362 .write_property(
1363 PropertyIdentifier::STATE_TEXT,
1364 Some(4),
1365 PropertyValue::CharacterString("X".into()),
1366 None,
1367 )
1368 .is_err());
1369 assert!(msi
1371 .write_property(
1372 PropertyIdentifier::STATE_TEXT,
1373 None,
1374 PropertyValue::CharacterString("X".into()),
1375 None,
1376 )
1377 .is_err());
1378 }
1379
1380 #[test]
1381 fn msi_state_text_in_property_list() {
1382 let msi = MultiStateInputObject::new(1, "MSI-1", 3).unwrap();
1383 assert!(msi
1384 .property_list()
1385 .contains(&PropertyIdentifier::STATE_TEXT));
1386 }
1387
1388 #[test]
1389 fn mso_state_text_defaults() {
1390 let mso = MultiStateOutputObject::new(1, "MSO-1", 2).unwrap();
1391 let val = mso
1392 .read_property(PropertyIdentifier::STATE_TEXT, None)
1393 .unwrap();
1394 assert_eq!(
1395 val,
1396 PropertyValue::List(vec![
1397 PropertyValue::CharacterString("State 1".into()),
1398 PropertyValue::CharacterString("State 2".into()),
1399 ])
1400 );
1401 }
1402
1403 #[test]
1404 fn mso_state_text_index_zero_returns_length() {
1405 let mso = MultiStateOutputObject::new(1, "MSO-1", 5).unwrap();
1406 let val = mso
1407 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1408 .unwrap();
1409 assert_eq!(val, PropertyValue::Unsigned(5));
1410 }
1411
1412 #[test]
1413 fn mso_state_text_valid_index() {
1414 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1415 let val = mso
1416 .read_property(PropertyIdentifier::STATE_TEXT, Some(3))
1417 .unwrap();
1418 assert_eq!(val, PropertyValue::CharacterString("State 3".into()));
1419 }
1420
1421 #[test]
1422 fn mso_state_text_invalid_index_error() {
1423 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1424 assert!(mso
1425 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1426 .is_err());
1427 }
1428
1429 #[test]
1430 fn mso_state_text_write_at_index() {
1431 let mut mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1432 mso.write_property(
1433 PropertyIdentifier::STATE_TEXT,
1434 Some(1),
1435 PropertyValue::CharacterString("Low".into()),
1436 None,
1437 )
1438 .unwrap();
1439 assert_eq!(
1440 mso.read_property(PropertyIdentifier::STATE_TEXT, Some(1))
1441 .unwrap(),
1442 PropertyValue::CharacterString("Low".into())
1443 );
1444 }
1445
1446 #[test]
1447 fn mso_state_text_in_property_list() {
1448 let mso = MultiStateOutputObject::new(1, "MSO-1", 3).unwrap();
1449 assert!(mso
1450 .property_list()
1451 .contains(&PropertyIdentifier::STATE_TEXT));
1452 }
1453
1454 #[test]
1455 fn msv_state_text_defaults() {
1456 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1457 let val = msv
1458 .read_property(PropertyIdentifier::STATE_TEXT, None)
1459 .unwrap();
1460 assert_eq!(
1461 val,
1462 PropertyValue::List(vec![
1463 PropertyValue::CharacterString("State 1".into()),
1464 PropertyValue::CharacterString("State 2".into()),
1465 PropertyValue::CharacterString("State 3".into()),
1466 ])
1467 );
1468 }
1469
1470 #[test]
1471 fn msv_state_text_index_zero_returns_length() {
1472 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1473 let val = msv
1474 .read_property(PropertyIdentifier::STATE_TEXT, Some(0))
1475 .unwrap();
1476 assert_eq!(val, PropertyValue::Unsigned(3));
1477 }
1478
1479 #[test]
1480 fn msv_state_text_valid_index() {
1481 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1482 let val = msv
1483 .read_property(PropertyIdentifier::STATE_TEXT, Some(1))
1484 .unwrap();
1485 assert_eq!(val, PropertyValue::CharacterString("State 1".into()));
1486 }
1487
1488 #[test]
1489 fn msv_state_text_invalid_index_error() {
1490 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1491 assert!(msv
1492 .read_property(PropertyIdentifier::STATE_TEXT, Some(4))
1493 .is_err());
1494 assert!(msv
1495 .read_property(PropertyIdentifier::STATE_TEXT, Some(0xFF))
1496 .is_err());
1497 }
1498
1499 #[test]
1500 fn msv_state_text_write_at_index() {
1501 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1502 msv.write_property(
1503 PropertyIdentifier::STATE_TEXT,
1504 Some(2),
1505 PropertyValue::CharacterString("Comfort".into()),
1506 None,
1507 )
1508 .unwrap();
1509 assert_eq!(
1510 msv.read_property(PropertyIdentifier::STATE_TEXT, Some(2))
1511 .unwrap(),
1512 PropertyValue::CharacterString("Comfort".into())
1513 );
1514 }
1515
1516 #[test]
1517 fn msv_state_text_write_bad_index_rejected() {
1518 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1519 assert!(msv
1520 .write_property(
1521 PropertyIdentifier::STATE_TEXT,
1522 None,
1523 PropertyValue::CharacterString("X".into()),
1524 None,
1525 )
1526 .is_err());
1527 assert!(msv
1528 .write_property(
1529 PropertyIdentifier::STATE_TEXT,
1530 Some(0),
1531 PropertyValue::CharacterString("X".into()),
1532 None,
1533 )
1534 .is_err());
1535 assert!(msv
1536 .write_property(
1537 PropertyIdentifier::STATE_TEXT,
1538 Some(4),
1539 PropertyValue::CharacterString("X".into()),
1540 None,
1541 )
1542 .is_err());
1543 }
1544
1545 #[test]
1546 fn msv_state_text_write_wrong_type_rejected() {
1547 let mut msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1548 assert!(msv
1549 .write_property(
1550 PropertyIdentifier::STATE_TEXT,
1551 Some(1),
1552 PropertyValue::Unsigned(1),
1553 None,
1554 )
1555 .is_err());
1556 }
1557
1558 #[test]
1559 fn msv_state_text_in_property_list() {
1560 let msv = MultiStateValueObject::new(1, "MSV-1", 3).unwrap();
1561 assert!(msv
1562 .property_list()
1563 .contains(&PropertyIdentifier::STATE_TEXT));
1564 }
1565}