1use bacnet_encoding::{primitives, tags};
8use bacnet_types::constructed::{BACnetDeviceObjectPropertyReference, BACnetPropertyStates};
9use bacnet_types::error::Error;
10use bacnet_types::primitives::{BACnetTimeStamp, Date, ObjectIdentifier, Time};
11use bytes::BytesMut;
12
13#[derive(Debug, Clone, PartialEq)]
19pub struct AcknowledgeAlarmRequest {
20 pub acknowledging_process_identifier: u32,
21 pub event_object_identifier: ObjectIdentifier,
22 pub event_state_acknowledged: u32,
23 pub timestamp: BACnetTimeStamp,
24 pub acknowledgment_source: String,
25}
26
27impl AcknowledgeAlarmRequest {
28 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
29 primitives::encode_ctx_unsigned(buf, 0, self.acknowledging_process_identifier as u64);
31 primitives::encode_ctx_object_id(buf, 1, &self.event_object_identifier);
33 primitives::encode_ctx_enumerated(buf, 2, self.event_state_acknowledged);
35 primitives::encode_timestamp(buf, 3, &self.timestamp);
37 primitives::encode_ctx_character_string(buf, 4, &self.acknowledgment_source)?;
39 Ok(())
40 }
41
42 pub fn decode(data: &[u8]) -> Result<Self, Error> {
43 let mut offset = 0;
44
45 let (_tag, pos) = tags::decode_tag(data, offset)?;
47 let end = pos + _tag.length as usize;
48 if end > data.len() {
49 return Err(Error::decoding(
50 pos,
51 "AcknowledgeAlarm truncated at process-id",
52 ));
53 }
54 let acknowledging_process_identifier = primitives::decode_unsigned(&data[pos..end])? as u32;
55 offset = end;
56
57 let (_tag, pos) = tags::decode_tag(data, offset)?;
59 let end = pos + _tag.length as usize;
60 if end > data.len() {
61 return Err(Error::decoding(
62 pos,
63 "AcknowledgeAlarm truncated at object-id",
64 ));
65 }
66 let event_object_identifier = ObjectIdentifier::decode(&data[pos..end])?;
67 offset = end;
68
69 let (_tag, pos) = tags::decode_tag(data, offset)?;
71 let end = pos + _tag.length as usize;
72 if end > data.len() {
73 return Err(Error::decoding(
74 pos,
75 "AcknowledgeAlarm truncated at event-state",
76 ));
77 }
78 let event_state_acknowledged = primitives::decode_unsigned(&data[pos..end])? as u32;
79 offset = end;
80
81 let (timestamp, new_offset) = primitives::decode_timestamp(data, offset, 3)?;
83 offset = new_offset;
84
85 let (opt_data, _new_offset) = tags::decode_optional_context(data, offset, 4)?;
87 let acknowledgment_source = match opt_data {
88 Some(content) => primitives::decode_character_string(content)?,
89 None => {
90 return Err(Error::decoding(
91 offset,
92 "AcknowledgeAlarm missing required acknowledgment-source [4]",
93 ))
94 }
95 };
96
97 Ok(Self {
98 acknowledging_process_identifier,
99 event_object_identifier,
100 event_state_acknowledged,
101 timestamp,
102 acknowledgment_source,
103 })
104 }
105}
106
107#[derive(Debug, Clone)]
116pub struct EventNotificationRequest {
117 pub process_identifier: u32,
119 pub initiating_device_identifier: ObjectIdentifier,
121 pub event_object_identifier: ObjectIdentifier,
123 pub timestamp: BACnetTimeStamp,
125 pub notification_class: u32,
127 pub priority: u8,
129 pub event_type: u32,
131 pub notify_type: u32,
133 pub ack_required: bool,
135 pub from_state: u32,
137 pub to_state: u32,
139 pub event_values: Option<NotificationParameters>,
141}
142
143impl EventNotificationRequest {
144 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
145 primitives::encode_ctx_unsigned(buf, 0, self.process_identifier as u64);
147 primitives::encode_ctx_object_id(buf, 1, &self.initiating_device_identifier);
149 primitives::encode_ctx_object_id(buf, 2, &self.event_object_identifier);
151 primitives::encode_timestamp(buf, 3, &self.timestamp);
153 primitives::encode_ctx_unsigned(buf, 4, self.notification_class as u64);
155 primitives::encode_ctx_unsigned(buf, 5, self.priority as u64);
157 primitives::encode_ctx_enumerated(buf, 6, self.event_type);
159 primitives::encode_ctx_enumerated(buf, 8, self.notify_type);
162 if self.notify_type != 2 {
164 primitives::encode_ctx_boolean(buf, 9, self.ack_required);
165 }
166 primitives::encode_ctx_enumerated(buf, 10, self.from_state);
168 primitives::encode_ctx_enumerated(buf, 11, self.to_state);
170 if let Some(ref params) = self.event_values {
172 tags::encode_opening_tag(buf, 12);
173 params.encode(buf)?;
174 tags::encode_closing_tag(buf, 12);
175 }
176 Ok(())
177 }
178
179 pub fn decode(data: &[u8]) -> Result<Self, Error> {
180 let mut offset = 0;
181
182 macro_rules! check_bounds {
184 ($pos:expr, $end:expr, $field:expr) => {
185 if $end > data.len() {
186 return Err(Error::decoding(
187 $pos,
188 concat!("EventNotification truncated at ", $field),
189 ));
190 }
191 };
192 }
193
194 let (_tag, pos) = tags::decode_tag(data, offset)?;
196 let end = pos + _tag.length as usize;
197 check_bounds!(pos, end, "processIdentifier");
198 let process_identifier = primitives::decode_unsigned(&data[pos..end])? as u32;
199 offset = end;
200
201 let (_tag, pos) = tags::decode_tag(data, offset)?;
203 let end = pos + _tag.length as usize;
204 check_bounds!(pos, end, "initiatingDeviceIdentifier");
205 let initiating_device_identifier = ObjectIdentifier::decode(&data[pos..end])?;
206 offset = end;
207
208 let (_tag, pos) = tags::decode_tag(data, offset)?;
210 let end = pos + _tag.length as usize;
211 check_bounds!(pos, end, "eventObjectIdentifier");
212 let event_object_identifier = ObjectIdentifier::decode(&data[pos..end])?;
213 offset = end;
214
215 let (timestamp, new_offset) = primitives::decode_timestamp(data, offset, 3)?;
217 offset = new_offset;
218
219 let (_tag, pos) = tags::decode_tag(data, offset)?;
221 let end = pos + _tag.length as usize;
222 check_bounds!(pos, end, "notificationClass");
223 let notification_class = primitives::decode_unsigned(&data[pos..end])? as u32;
224 offset = end;
225
226 let (_tag, pos) = tags::decode_tag(data, offset)?;
228 let end = pos + _tag.length as usize;
229 check_bounds!(pos, end, "priority");
230 let priority = primitives::decode_unsigned(&data[pos..end])? as u8;
231 offset = end;
232
233 let (_tag, pos) = tags::decode_tag(data, offset)?;
235 let end = pos + _tag.length as usize;
236 check_bounds!(pos, end, "eventType");
237 let event_type = primitives::decode_unsigned(&data[pos..end])? as u32;
238 offset = end;
239
240 while offset < data.len() {
242 let (peek, peek_pos) = tags::decode_tag(data, offset)?;
243 if peek.is_context(8) {
244 break;
245 }
246 if peek.is_opening {
247 let (_, new_offset) = tags::extract_context_value(data, peek_pos, peek.number)?;
249 offset = new_offset;
250 } else if peek.is_closing {
251 return Err(Error::decoding(
252 offset,
253 "unexpected closing tag skipping to notification-parameters",
254 ));
255 } else {
256 let skip_end = peek_pos + peek.length as usize;
257 if skip_end > data.len() {
258 return Err(Error::decoding(
259 peek_pos,
260 "EventNotification truncated skipping messageText",
261 ));
262 }
263 offset = skip_end;
264 }
265 }
266
267 let (_tag, pos) = tags::decode_tag(data, offset)?;
269 let end = pos + _tag.length as usize;
270 check_bounds!(pos, end, "notifyType");
271 let notify_type = primitives::decode_unsigned(&data[pos..end])? as u32;
272 offset = end;
273
274 let mut ack_required = false;
276 if offset < data.len() {
277 let (peek, peek_pos) = tags::decode_tag(data, offset)?;
278 if peek.is_context(9) {
279 let end = peek_pos + peek.length as usize;
280 check_bounds!(peek_pos, end, "ackRequired");
281 ack_required = data[peek_pos] != 0;
282 offset = end;
283 }
284 }
285
286 let (_tag, pos) = tags::decode_tag(data, offset)?;
288 let end = pos + _tag.length as usize;
289 check_bounds!(pos, end, "fromState");
290 let from_state = primitives::decode_unsigned(&data[pos..end])? as u32;
291 offset = end;
292
293 let (_tag, pos) = tags::decode_tag(data, offset)?;
295 let end = pos + _tag.length as usize;
296 check_bounds!(pos, end, "toState");
297 let to_state = primitives::decode_unsigned(&data[pos..end])? as u32;
298 offset = end;
299
300 let mut event_values = None;
302 if offset < data.len() {
303 let (peek, _) = tags::decode_tag(data, offset)?;
304 if peek.is_opening && peek.number == 12 {
305 let (_, inner_start) = tags::decode_tag(data, offset)?;
307 event_values = Some(NotificationParameters::decode(data, inner_start)?);
308 let mut scan = inner_start;
310 let mut depth: usize = 1;
311 while depth > 0 && scan < data.len() {
312 let (t, next) = tags::decode_tag(data, scan)?;
313 if t.is_opening {
314 depth += 1;
315 scan = next;
316 } else if t.is_closing {
317 depth -= 1;
318 if depth == 0 {
319 offset = next;
320 } else {
321 scan = next;
322 }
323 } else {
324 let end = next.saturating_add(t.length as usize);
325 if end > data.len() {
326 return Err(Error::decoding(
327 next,
328 "EventNotification: truncated tag in eventValues",
329 ));
330 }
331 scan = end;
332 }
333 }
334 }
335 }
336 let _ = offset;
337
338 Ok(Self {
339 process_identifier,
340 initiating_device_identifier,
341 event_object_identifier,
342 timestamp,
343 notification_class,
344 priority,
345 event_type,
346 notify_type,
347 ack_required,
348 from_state,
349 to_state,
350 event_values,
351 })
352 }
353}
354
355#[derive(Debug, Clone, PartialEq)]
361pub enum NotificationParameters {
362 ChangeOfBitstring {
364 referenced_bitstring: (u8, Vec<u8>),
365 status_flags: u8,
366 },
367 ChangeOfState {
369 new_state: BACnetPropertyStates,
370 status_flags: u8,
371 },
372 ChangeOfValue {
374 new_value: ChangeOfValueChoice,
375 status_flags: u8,
376 },
377 CommandFailure {
379 command_value: Vec<u8>,
380 status_flags: u8,
381 feedback_value: Vec<u8>,
382 },
383 FloatingLimit {
385 reference_value: f32,
386 status_flags: u8,
387 setpoint_value: f32,
388 error_limit: f32,
389 },
390 OutOfRange {
392 exceeding_value: f32,
393 status_flags: u8,
394 deadband: f32,
395 exceeded_limit: f32,
396 },
397 ChangeOfLifeSafety {
399 new_state: u32,
400 new_mode: u32,
401 status_flags: u8,
402 operation_expected: u32,
403 },
404 Extended {
406 vendor_id: u16,
407 extended_event_type: u32,
408 parameters: Vec<u8>,
409 },
410 BufferReady {
412 buffer_property: BACnetDeviceObjectPropertyReference,
413 previous_notification: u32,
414 current_notification: u32,
415 },
416 UnsignedRange {
418 exceeding_value: u64,
419 status_flags: u8,
420 exceeded_limit: u64,
421 },
422 AccessEvent {
424 access_event: u32,
425 status_flags: u8,
426 access_event_tag: u32,
427 access_event_time: (Date, Time),
428 access_credential: BACnetDeviceObjectPropertyReference,
429 authentication_factor: Vec<u8>,
430 },
431 DoubleOutOfRange {
433 exceeding_value: f64,
434 status_flags: u8,
435 deadband: f64,
436 exceeded_limit: f64,
437 },
438 SignedOutOfRange {
440 exceeding_value: i32,
441 status_flags: u8,
442 deadband: u64,
443 exceeded_limit: i32,
444 },
445 UnsignedOutOfRange {
447 exceeding_value: u64,
448 status_flags: u8,
449 deadband: u64,
450 exceeded_limit: u64,
451 },
452 ChangeOfCharacterstring {
454 changed_value: String,
455 status_flags: u8,
456 alarm_value: String,
457 },
458 ChangeOfStatusFlags {
460 present_value: Vec<u8>,
461 referenced_flags: u8,
462 },
463 ChangeOfReliability {
465 reliability: u32,
466 status_flags: u8,
467 property_values: Vec<u8>,
468 },
469 NoneParams,
471 ChangeOfDiscreteValue {
473 new_value: Vec<u8>,
474 status_flags: u8,
475 },
476 ChangeOfTimer {
478 new_state: u32,
479 status_flags: u8,
480 update_time: (Date, Time),
481 last_state_change: u32,
482 initial_timeout: u32,
483 expiration_time: (Date, Time),
484 },
485}
486
487#[derive(Debug, Clone, PartialEq)]
489pub enum ChangeOfValueChoice {
490 ChangedBits { unused_bits: u8, data: Vec<u8> },
491 ChangedValue(f32),
492}
493
494impl NotificationParameters {
495 pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
500 match self {
501 Self::ChangeOfBitstring {
502 referenced_bitstring,
503 status_flags,
504 } => {
505 tags::encode_opening_tag(buf, 0);
506 primitives::encode_ctx_bit_string(
507 buf,
508 0,
509 referenced_bitstring.0,
510 &referenced_bitstring.1,
511 );
512 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
513 tags::encode_closing_tag(buf, 0);
514 }
515 Self::ChangeOfState {
516 new_state,
517 status_flags,
518 } => {
519 tags::encode_opening_tag(buf, 1);
520 tags::encode_opening_tag(buf, 0);
522 encode_property_states(buf, new_state);
523 tags::encode_closing_tag(buf, 0);
524 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
526 tags::encode_closing_tag(buf, 1);
527 }
528 Self::ChangeOfValue {
529 new_value,
530 status_flags,
531 } => {
532 tags::encode_opening_tag(buf, 2);
533 tags::encode_opening_tag(buf, 0);
535 match new_value {
536 ChangeOfValueChoice::ChangedBits { unused_bits, data } => {
537 primitives::encode_ctx_bit_string(buf, 0, *unused_bits, data);
538 }
539 ChangeOfValueChoice::ChangedValue(v) => {
540 primitives::encode_ctx_real(buf, 1, *v);
541 }
542 }
543 tags::encode_closing_tag(buf, 0);
544 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
546 tags::encode_closing_tag(buf, 2);
547 }
548 Self::CommandFailure {
549 command_value,
550 status_flags,
551 feedback_value,
552 } => {
553 tags::encode_opening_tag(buf, 3);
554 tags::encode_opening_tag(buf, 0);
556 buf.extend_from_slice(command_value);
557 tags::encode_closing_tag(buf, 0);
558 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
560 tags::encode_opening_tag(buf, 2);
562 buf.extend_from_slice(feedback_value);
563 tags::encode_closing_tag(buf, 2);
564 tags::encode_closing_tag(buf, 3);
565 }
566 Self::FloatingLimit {
567 reference_value,
568 status_flags,
569 setpoint_value,
570 error_limit,
571 } => {
572 tags::encode_opening_tag(buf, 4);
573 primitives::encode_ctx_real(buf, 0, *reference_value);
574 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
575 primitives::encode_ctx_real(buf, 2, *setpoint_value);
576 primitives::encode_ctx_real(buf, 3, *error_limit);
577 tags::encode_closing_tag(buf, 4);
578 }
579 Self::OutOfRange {
580 exceeding_value,
581 status_flags,
582 deadband,
583 exceeded_limit,
584 } => {
585 tags::encode_opening_tag(buf, 5);
586 primitives::encode_ctx_real(buf, 0, *exceeding_value);
587 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
588 primitives::encode_ctx_real(buf, 2, *deadband);
589 primitives::encode_ctx_real(buf, 3, *exceeded_limit);
590 tags::encode_closing_tag(buf, 5);
591 }
592 Self::ChangeOfLifeSafety {
593 new_state,
594 new_mode,
595 status_flags,
596 operation_expected,
597 } => {
598 tags::encode_opening_tag(buf, 8);
599 primitives::encode_ctx_enumerated(buf, 0, *new_state);
600 primitives::encode_ctx_enumerated(buf, 1, *new_mode);
601 primitives::encode_ctx_bit_string(buf, 2, 4, &[*status_flags << 4]);
602 primitives::encode_ctx_enumerated(buf, 3, *operation_expected);
603 tags::encode_closing_tag(buf, 8);
604 }
605 Self::Extended {
606 vendor_id,
607 extended_event_type,
608 parameters,
609 } => {
610 tags::encode_opening_tag(buf, 9);
611 primitives::encode_ctx_unsigned(buf, 0, *vendor_id as u64);
612 primitives::encode_ctx_unsigned(buf, 1, *extended_event_type as u64);
613 tags::encode_opening_tag(buf, 2);
615 buf.extend_from_slice(parameters);
616 tags::encode_closing_tag(buf, 2);
617 tags::encode_closing_tag(buf, 9);
618 }
619 Self::BufferReady {
620 buffer_property,
621 previous_notification,
622 current_notification,
623 } => {
624 tags::encode_opening_tag(buf, 10);
625 tags::encode_opening_tag(buf, 0);
627 primitives::encode_ctx_object_id(buf, 0, &buffer_property.object_identifier);
628 primitives::encode_ctx_unsigned(buf, 1, buffer_property.property_identifier as u64);
629 if let Some(idx) = buffer_property.property_array_index {
630 primitives::encode_ctx_unsigned(buf, 2, idx as u64);
631 }
632 if let Some(ref dev) = buffer_property.device_identifier {
633 primitives::encode_ctx_object_id(buf, 3, dev);
634 }
635 tags::encode_closing_tag(buf, 0);
636 primitives::encode_ctx_unsigned(buf, 1, *previous_notification as u64);
638 primitives::encode_ctx_unsigned(buf, 2, *current_notification as u64);
640 tags::encode_closing_tag(buf, 10);
641 }
642 Self::UnsignedRange {
643 exceeding_value,
644 status_flags,
645 exceeded_limit,
646 } => {
647 tags::encode_opening_tag(buf, 11);
648 primitives::encode_ctx_unsigned(buf, 0, *exceeding_value);
649 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
650 primitives::encode_ctx_unsigned(buf, 2, *exceeded_limit);
651 tags::encode_closing_tag(buf, 11);
652 }
653 Self::AccessEvent {
654 access_event,
655 status_flags,
656 access_event_tag,
657 access_event_time,
658 access_credential,
659 authentication_factor,
660 } => {
661 tags::encode_opening_tag(buf, 13);
662 primitives::encode_ctx_enumerated(buf, 0, *access_event);
663 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
664 primitives::encode_ctx_unsigned(buf, 2, *access_event_tag as u64);
665 primitives::encode_timestamp(
667 buf,
668 3,
669 &BACnetTimeStamp::DateTime {
670 date: access_event_time.0,
671 time: access_event_time.1,
672 },
673 );
674 tags::encode_opening_tag(buf, 4);
676 primitives::encode_ctx_object_id(buf, 0, &access_credential.object_identifier);
677 primitives::encode_ctx_unsigned(
678 buf,
679 1,
680 access_credential.property_identifier as u64,
681 );
682 if let Some(idx) = access_credential.property_array_index {
683 primitives::encode_ctx_unsigned(buf, 2, idx as u64);
684 }
685 if let Some(ref dev) = access_credential.device_identifier {
686 primitives::encode_ctx_object_id(buf, 3, dev);
687 }
688 tags::encode_closing_tag(buf, 4);
689 tags::encode_opening_tag(buf, 5);
691 buf.extend_from_slice(authentication_factor);
692 tags::encode_closing_tag(buf, 5);
693 tags::encode_closing_tag(buf, 13);
694 }
695 Self::DoubleOutOfRange {
696 exceeding_value,
697 status_flags,
698 deadband,
699 exceeded_limit,
700 } => {
701 tags::encode_opening_tag(buf, 14);
702 primitives::encode_ctx_double(buf, 0, *exceeding_value);
703 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
704 primitives::encode_ctx_double(buf, 2, *deadband);
705 primitives::encode_ctx_double(buf, 3, *exceeded_limit);
706 tags::encode_closing_tag(buf, 14);
707 }
708 Self::SignedOutOfRange {
709 exceeding_value,
710 status_flags,
711 deadband,
712 exceeded_limit,
713 } => {
714 tags::encode_opening_tag(buf, 15);
715 primitives::encode_ctx_signed(buf, 0, *exceeding_value);
716 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
717 primitives::encode_ctx_unsigned(buf, 2, *deadband);
718 primitives::encode_ctx_signed(buf, 3, *exceeded_limit);
719 tags::encode_closing_tag(buf, 15);
720 }
721 Self::UnsignedOutOfRange {
722 exceeding_value,
723 status_flags,
724 deadband,
725 exceeded_limit,
726 } => {
727 tags::encode_opening_tag(buf, 16);
728 primitives::encode_ctx_unsigned(buf, 0, *exceeding_value);
729 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
730 primitives::encode_ctx_unsigned(buf, 2, *deadband);
731 primitives::encode_ctx_unsigned(buf, 3, *exceeded_limit);
732 tags::encode_closing_tag(buf, 16);
733 }
734 Self::ChangeOfCharacterstring {
735 changed_value,
736 status_flags,
737 alarm_value,
738 } => {
739 tags::encode_opening_tag(buf, 17);
740 primitives::encode_ctx_character_string(buf, 0, changed_value)?;
741 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
742 primitives::encode_ctx_character_string(buf, 2, alarm_value)?;
743 tags::encode_closing_tag(buf, 17);
744 }
745 Self::ChangeOfStatusFlags {
746 present_value,
747 referenced_flags,
748 } => {
749 tags::encode_opening_tag(buf, 18);
750 tags::encode_opening_tag(buf, 0);
752 buf.extend_from_slice(present_value);
753 tags::encode_closing_tag(buf, 0);
754 primitives::encode_ctx_bit_string(buf, 1, 4, &[*referenced_flags << 4]);
756 tags::encode_closing_tag(buf, 18);
757 }
758 Self::ChangeOfReliability {
759 reliability,
760 status_flags,
761 property_values,
762 } => {
763 tags::encode_opening_tag(buf, 19);
764 primitives::encode_ctx_enumerated(buf, 0, *reliability);
765 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
766 tags::encode_opening_tag(buf, 2);
768 buf.extend_from_slice(property_values);
769 tags::encode_closing_tag(buf, 2);
770 tags::encode_closing_tag(buf, 19);
771 }
772 Self::NoneParams => {
773 tags::encode_opening_tag(buf, 20);
774 tags::encode_closing_tag(buf, 20);
775 }
776 Self::ChangeOfDiscreteValue {
777 new_value,
778 status_flags,
779 } => {
780 tags::encode_opening_tag(buf, 21);
781 tags::encode_opening_tag(buf, 0);
783 buf.extend_from_slice(new_value);
784 tags::encode_closing_tag(buf, 0);
785 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
787 tags::encode_closing_tag(buf, 21);
788 }
789 Self::ChangeOfTimer {
790 new_state,
791 status_flags,
792 update_time,
793 last_state_change,
794 initial_timeout,
795 expiration_time,
796 } => {
797 tags::encode_opening_tag(buf, 22);
798 primitives::encode_ctx_enumerated(buf, 0, *new_state);
799 primitives::encode_ctx_bit_string(buf, 1, 4, &[*status_flags << 4]);
800 tags::encode_opening_tag(buf, 2);
802 primitives::encode_app_date(buf, &update_time.0);
803 primitives::encode_app_time(buf, &update_time.1);
804 tags::encode_closing_tag(buf, 2);
805 primitives::encode_ctx_enumerated(buf, 3, *last_state_change);
807 primitives::encode_ctx_unsigned(buf, 4, *initial_timeout as u64);
809 tags::encode_opening_tag(buf, 5);
811 primitives::encode_app_date(buf, &expiration_time.0);
812 primitives::encode_app_time(buf, &expiration_time.1);
813 tags::encode_closing_tag(buf, 5);
814 tags::encode_closing_tag(buf, 22);
815 }
816 }
817 Ok(())
818 }
819
820 pub fn decode(data: &[u8], offset: usize) -> Result<Self, Error> {
823 if offset >= data.len() {
825 return Err(Error::decoding(
826 offset,
827 "NotificationParameters: empty payload",
828 ));
829 }
830 let (inner_tag, inner_start) = tags::decode_tag(data, offset)?;
831 if !inner_tag.is_opening {
832 return Err(Error::decoding(
833 offset,
834 "NotificationParameters: expected opening tag for variant",
835 ));
836 }
837 let variant_tag = inner_tag.number;
838
839 match variant_tag {
840 1 => {
842 let mut pos = inner_start;
843 let (t, p) = tags::decode_tag(data, pos)?;
845 if !t.is_opening || t.number != 0 {
846 return Err(Error::decoding(
847 pos,
848 "ChangeOfState: expected opening tag [0] for new-state",
849 ));
850 }
851 pos = p;
852 let new_state = decode_property_states(data, &mut pos)?;
853 let (ct, cp) = tags::decode_tag(data, pos)?;
855 if !ct.is_closing || ct.number != 0 {
856 return Err(Error::decoding(pos, "ChangeOfState: expected closing [0]"));
857 }
858 pos = cp;
859 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
861 let sf_end = sf_pos + sf_tag.length as usize;
862 if sf_end > data.len() {
863 return Err(Error::decoding(sf_pos, "ChangeOfState: truncated flags"));
864 }
865 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
866 Ok(Self::ChangeOfState {
867 new_state,
868 status_flags,
869 })
870 }
871 2 => {
873 let mut pos = inner_start;
874 let (t, p) = tags::decode_tag(data, pos)?;
876 if !t.is_opening || t.number != 0 {
877 return Err(Error::decoding(
878 pos,
879 "ChangeOfValue: expected opening [0] for new-value",
880 ));
881 }
882 pos = p;
883 let (choice_tag, choice_pos) = tags::decode_tag(data, pos)?;
885 let new_value = if choice_tag.number == 0 {
886 let end = choice_pos + choice_tag.length as usize;
888 if end > data.len() {
889 return Err(Error::decoding(choice_pos, "ChangeOfValue: truncated bits"));
890 }
891 let (unused, bits) = primitives::decode_bit_string(&data[choice_pos..end])?;
892 pos = end;
893 ChangeOfValueChoice::ChangedBits {
894 unused_bits: unused,
895 data: bits,
896 }
897 } else {
898 let end = choice_pos + choice_tag.length as usize;
900 if end > data.len() {
901 return Err(Error::decoding(choice_pos, "ChangeOfValue: truncated real"));
902 }
903 let v = primitives::decode_real(&data[choice_pos..end])?;
904 pos = end;
905 ChangeOfValueChoice::ChangedValue(v)
906 };
907 let (ct, cp) = tags::decode_tag(data, pos)?;
909 if !ct.is_closing || ct.number != 0 {
910 return Err(Error::decoding(pos, "ChangeOfValue: expected closing [0]"));
911 }
912 pos = cp;
913 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
915 let sf_end = sf_pos + sf_tag.length as usize;
916 if sf_end > data.len() {
917 return Err(Error::decoding(sf_pos, "ChangeOfValue: truncated flags"));
918 }
919 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
920 Ok(Self::ChangeOfValue {
921 new_value,
922 status_flags,
923 })
924 }
925 5 => {
927 let mut pos = inner_start;
928 let (t, p) = tags::decode_tag(data, pos)?;
930 let end = p + t.length as usize;
931 if end > data.len() {
932 return Err(Error::decoding(p, "OutOfRange: truncated exceeding_value"));
933 }
934 let exceeding_value = primitives::decode_real(&data[p..end])?;
935 pos = end;
936 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
938 let sf_end = sf_pos + sf_tag.length as usize;
939 if sf_end > data.len() {
940 return Err(Error::decoding(sf_pos, "OutOfRange: truncated flags"));
941 }
942 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
943 pos = sf_end;
944 let (t, p) = tags::decode_tag(data, pos)?;
946 let end = p + t.length as usize;
947 if end > data.len() {
948 return Err(Error::decoding(p, "OutOfRange: truncated deadband"));
949 }
950 let deadband = primitives::decode_real(&data[p..end])?;
951 pos = end;
952 let (t, p) = tags::decode_tag(data, pos)?;
954 let end = p + t.length as usize;
955 if end > data.len() {
956 return Err(Error::decoding(p, "OutOfRange: truncated exceeded_limit"));
957 }
958 let exceeded_limit = primitives::decode_real(&data[p..end])?;
959 let _ = (pos, end);
960 Ok(Self::OutOfRange {
961 exceeding_value,
962 status_flags,
963 deadband,
964 exceeded_limit,
965 })
966 }
967 10 => {
969 let mut pos = inner_start;
970 let (t, p) = tags::decode_tag(data, pos)?;
972 if !t.is_opening || t.number != 0 {
973 return Err(Error::decoding(
974 pos,
975 "BufferReady: expected opening [0] for buffer-property",
976 ));
977 }
978 pos = p;
979 let buffer_property = decode_device_obj_prop_ref(data, &mut pos)?;
980 let (ct, cp) = tags::decode_tag(data, pos)?;
982 if !ct.is_closing || ct.number != 0 {
983 return Err(Error::decoding(pos, "BufferReady: expected closing [0]"));
984 }
985 pos = cp;
986 let (t, p) = tags::decode_tag(data, pos)?;
988 let end = p + t.length as usize;
989 if end > data.len() {
990 return Err(Error::decoding(
991 p,
992 "BufferReady: truncated previous_notification",
993 ));
994 }
995 let previous_notification = primitives::decode_unsigned(&data[p..end])? as u32;
996 pos = end;
997 let (t, p) = tags::decode_tag(data, pos)?;
999 let end = p + t.length as usize;
1000 if end > data.len() {
1001 return Err(Error::decoding(
1002 p,
1003 "BufferReady: truncated current_notification",
1004 ));
1005 }
1006 let current_notification = primitives::decode_unsigned(&data[p..end])? as u32;
1007 let _ = (pos, end);
1008 Ok(Self::BufferReady {
1009 buffer_property,
1010 previous_notification,
1011 current_notification,
1012 })
1013 }
1014 11 => {
1016 let mut pos = inner_start;
1017 let (t, p) = tags::decode_tag(data, pos)?;
1019 let end = p + t.length as usize;
1020 if end > data.len() {
1021 return Err(Error::decoding(
1022 p,
1023 "UnsignedRange: truncated exceeding_value",
1024 ));
1025 }
1026 let exceeding_value = primitives::decode_unsigned(&data[p..end])?;
1027 pos = end;
1028 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1030 let sf_end = sf_pos + sf_tag.length as usize;
1031 if sf_end > data.len() {
1032 return Err(Error::decoding(sf_pos, "UnsignedRange: truncated flags"));
1033 }
1034 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1035 pos = sf_end;
1036 let (t, p) = tags::decode_tag(data, pos)?;
1038 let end = p + t.length as usize;
1039 if end > data.len() {
1040 return Err(Error::decoding(
1041 p,
1042 "UnsignedRange: truncated exceeded_limit",
1043 ));
1044 }
1045 let exceeded_limit = primitives::decode_unsigned(&data[p..end])?;
1046 let _ = (pos, end);
1047 Ok(Self::UnsignedRange {
1048 exceeding_value,
1049 status_flags,
1050 exceeded_limit,
1051 })
1052 }
1053 0 => {
1055 let mut pos = inner_start;
1056 let (t, p) = tags::decode_tag(data, pos)?;
1058 let end = p + t.length as usize;
1059 if end > data.len() {
1060 return Err(Error::decoding(p, "ChangeOfBitstring: truncated bitstring"));
1061 }
1062 let (unused, bits) = primitives::decode_bit_string(&data[p..end])?;
1063 pos = end;
1064 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1066 let sf_end = sf_pos + sf_tag.length as usize;
1067 if sf_end > data.len() {
1068 return Err(Error::decoding(
1069 sf_pos,
1070 "ChangeOfBitstring: truncated flags",
1071 ));
1072 }
1073 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1074 Ok(Self::ChangeOfBitstring {
1075 referenced_bitstring: (unused, bits),
1076 status_flags,
1077 })
1078 }
1079 3 => {
1081 let mut pos = inner_start;
1082 let (t, p) = tags::decode_tag(data, pos)?;
1084 if !t.is_opening || t.number != 0 {
1085 return Err(Error::decoding(pos, "CommandFailure: expected opening [0]"));
1086 }
1087 let (command_value, after) = extract_raw_context(data, p, 0)?;
1088 pos = after;
1089 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1091 let sf_end = sf_pos + sf_tag.length as usize;
1092 if sf_end > data.len() {
1093 return Err(Error::decoding(sf_pos, "CommandFailure: truncated flags"));
1094 }
1095 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1096 pos = sf_end;
1097 let (t, p) = tags::decode_tag(data, pos)?;
1099 if !t.is_opening || t.number != 2 {
1100 return Err(Error::decoding(pos, "CommandFailure: expected opening [2]"));
1101 }
1102 let (feedback_value, _after) = extract_raw_context(data, p, 2)?;
1103 Ok(Self::CommandFailure {
1104 command_value,
1105 status_flags,
1106 feedback_value,
1107 })
1108 }
1109 4 => {
1111 let mut pos = inner_start;
1112 let (t, p) = tags::decode_tag(data, pos)?;
1114 let end = p + t.length as usize;
1115 if end > data.len() {
1116 return Err(Error::decoding(
1117 p,
1118 "FloatingLimit: truncated reference_value",
1119 ));
1120 }
1121 let reference_value = primitives::decode_real(&data[p..end])?;
1122 pos = end;
1123 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1125 let sf_end = sf_pos + sf_tag.length as usize;
1126 if sf_end > data.len() {
1127 return Err(Error::decoding(sf_pos, "FloatingLimit: truncated flags"));
1128 }
1129 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1130 pos = sf_end;
1131 let (t, p) = tags::decode_tag(data, pos)?;
1133 let end = p + t.length as usize;
1134 if end > data.len() {
1135 return Err(Error::decoding(
1136 p,
1137 "FloatingLimit: truncated setpoint_value",
1138 ));
1139 }
1140 let setpoint_value = primitives::decode_real(&data[p..end])?;
1141 pos = end;
1142 let (t, p) = tags::decode_tag(data, pos)?;
1144 let end = p + t.length as usize;
1145 if end > data.len() {
1146 return Err(Error::decoding(p, "FloatingLimit: truncated error_limit"));
1147 }
1148 let error_limit = primitives::decode_real(&data[p..end])?;
1149 let _ = (pos, end);
1150 Ok(Self::FloatingLimit {
1151 reference_value,
1152 status_flags,
1153 setpoint_value,
1154 error_limit,
1155 })
1156 }
1157 8 => {
1159 let mut pos = inner_start;
1160 let (t, p) = tags::decode_tag(data, pos)?;
1162 let end = p + t.length as usize;
1163 if end > data.len() {
1164 return Err(Error::decoding(
1165 p,
1166 "ChangeOfLifeSafety: truncated new_state",
1167 ));
1168 }
1169 let new_state = primitives::decode_unsigned(&data[p..end])? as u32;
1170 pos = end;
1171 let (t, p) = tags::decode_tag(data, pos)?;
1173 let end = p + t.length as usize;
1174 if end > data.len() {
1175 return Err(Error::decoding(p, "ChangeOfLifeSafety: truncated new_mode"));
1176 }
1177 let new_mode = primitives::decode_unsigned(&data[p..end])? as u32;
1178 pos = end;
1179 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1181 let sf_end = sf_pos + sf_tag.length as usize;
1182 if sf_end > data.len() {
1183 return Err(Error::decoding(
1184 sf_pos,
1185 "ChangeOfLifeSafety: truncated flags",
1186 ));
1187 }
1188 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1189 pos = sf_end;
1190 let (t, p) = tags::decode_tag(data, pos)?;
1192 let end = p + t.length as usize;
1193 if end > data.len() {
1194 return Err(Error::decoding(
1195 p,
1196 "ChangeOfLifeSafety: truncated operation_expected",
1197 ));
1198 }
1199 let operation_expected = primitives::decode_unsigned(&data[p..end])? as u32;
1200 let _ = (pos, end);
1201 Ok(Self::ChangeOfLifeSafety {
1202 new_state,
1203 new_mode,
1204 status_flags,
1205 operation_expected,
1206 })
1207 }
1208 9 => {
1210 let mut pos = inner_start;
1211 let (t, p) = tags::decode_tag(data, pos)?;
1213 let end = p + t.length as usize;
1214 if end > data.len() {
1215 return Err(Error::decoding(p, "Extended: truncated vendor_id"));
1216 }
1217 let vendor_id = primitives::decode_unsigned(&data[p..end])? as u16;
1218 pos = end;
1219 let (t, p) = tags::decode_tag(data, pos)?;
1221 let end = p + t.length as usize;
1222 if end > data.len() {
1223 return Err(Error::decoding(
1224 p,
1225 "Extended: truncated extended_event_type",
1226 ));
1227 }
1228 let extended_event_type = primitives::decode_unsigned(&data[p..end])? as u32;
1229 pos = end;
1230 let (t, p) = tags::decode_tag(data, pos)?;
1232 if !t.is_opening || t.number != 2 {
1233 return Err(Error::decoding(pos, "Extended: expected opening [2]"));
1234 }
1235 let (parameters, _after) = extract_raw_context(data, p, 2)?;
1236 Ok(Self::Extended {
1237 vendor_id,
1238 extended_event_type,
1239 parameters,
1240 })
1241 }
1242 13 => {
1244 let mut pos = inner_start;
1245 let (t, p) = tags::decode_tag(data, pos)?;
1247 let end = p + t.length as usize;
1248 if end > data.len() {
1249 return Err(Error::decoding(p, "AccessEvent: truncated access_event"));
1250 }
1251 let access_event = primitives::decode_unsigned(&data[p..end])? as u32;
1252 pos = end;
1253 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1255 let sf_end = sf_pos + sf_tag.length as usize;
1256 if sf_end > data.len() {
1257 return Err(Error::decoding(sf_pos, "AccessEvent: truncated flags"));
1258 }
1259 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1260 pos = sf_end;
1261 let (t, p) = tags::decode_tag(data, pos)?;
1263 let end = p + t.length as usize;
1264 if end > data.len() {
1265 return Err(Error::decoding(
1266 p,
1267 "AccessEvent: truncated access_event_tag",
1268 ));
1269 }
1270 let access_event_tag = primitives::decode_unsigned(&data[p..end])? as u32;
1271 pos = end;
1272 let (ts, new_pos) = primitives::decode_timestamp(data, pos, 3)?;
1274 pos = new_pos;
1275 let access_event_time = match ts {
1276 BACnetTimeStamp::DateTime { date, time } => (date, time),
1277 _ => {
1278 return Err(Error::decoding(
1279 pos,
1280 "AccessEvent: expected DateTime timestamp",
1281 ))
1282 }
1283 };
1284 let (t, p) = tags::decode_tag(data, pos)?;
1286 if !t.is_opening || t.number != 4 {
1287 return Err(Error::decoding(
1288 pos,
1289 "AccessEvent: expected opening [4] for access-credential",
1290 ));
1291 }
1292 pos = p;
1293 let access_credential = decode_device_obj_prop_ref(data, &mut pos)?;
1294 let (ct, cp) = tags::decode_tag(data, pos)?;
1295 if !ct.is_closing || ct.number != 4 {
1296 return Err(Error::decoding(pos, "AccessEvent: expected closing [4]"));
1297 }
1298 pos = cp;
1299 let (t, p) = tags::decode_tag(data, pos)?;
1301 if !t.is_opening || t.number != 5 {
1302 return Err(Error::decoding(
1303 pos,
1304 "AccessEvent: expected opening [5] for authentication-factor",
1305 ));
1306 }
1307 let (authentication_factor, _after) = extract_raw_context(data, p, 5)?;
1308 Ok(Self::AccessEvent {
1309 access_event,
1310 status_flags,
1311 access_event_tag,
1312 access_event_time,
1313 access_credential,
1314 authentication_factor,
1315 })
1316 }
1317 14 => {
1319 let mut pos = inner_start;
1320 let (t, p) = tags::decode_tag(data, pos)?;
1322 let end = p + t.length as usize;
1323 if end > data.len() {
1324 return Err(Error::decoding(
1325 p,
1326 "DoubleOutOfRange: truncated exceeding_value",
1327 ));
1328 }
1329 let exceeding_value = primitives::decode_double(&data[p..end])?;
1330 pos = end;
1331 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1333 let sf_end = sf_pos + sf_tag.length as usize;
1334 if sf_end > data.len() {
1335 return Err(Error::decoding(sf_pos, "DoubleOutOfRange: truncated flags"));
1336 }
1337 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1338 pos = sf_end;
1339 let (t, p) = tags::decode_tag(data, pos)?;
1341 let end = p + t.length as usize;
1342 if end > data.len() {
1343 return Err(Error::decoding(p, "DoubleOutOfRange: truncated deadband"));
1344 }
1345 let deadband = primitives::decode_double(&data[p..end])?;
1346 pos = end;
1347 let (t, p) = tags::decode_tag(data, pos)?;
1349 let end = p + t.length as usize;
1350 if end > data.len() {
1351 return Err(Error::decoding(
1352 p,
1353 "DoubleOutOfRange: truncated exceeded_limit",
1354 ));
1355 }
1356 let exceeded_limit = primitives::decode_double(&data[p..end])?;
1357 let _ = (pos, end);
1358 Ok(Self::DoubleOutOfRange {
1359 exceeding_value,
1360 status_flags,
1361 deadband,
1362 exceeded_limit,
1363 })
1364 }
1365 15 => {
1367 let mut pos = inner_start;
1368 let (t, p) = tags::decode_tag(data, pos)?;
1370 let end = p + t.length as usize;
1371 if end > data.len() {
1372 return Err(Error::decoding(
1373 p,
1374 "SignedOutOfRange: truncated exceeding_value",
1375 ));
1376 }
1377 let exceeding_value = primitives::decode_signed(&data[p..end])?;
1378 pos = end;
1379 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1381 let sf_end = sf_pos + sf_tag.length as usize;
1382 if sf_end > data.len() {
1383 return Err(Error::decoding(sf_pos, "SignedOutOfRange: truncated flags"));
1384 }
1385 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1386 pos = sf_end;
1387 let (t, p) = tags::decode_tag(data, pos)?;
1389 let end = p + t.length as usize;
1390 if end > data.len() {
1391 return Err(Error::decoding(p, "SignedOutOfRange: truncated deadband"));
1392 }
1393 let deadband = primitives::decode_unsigned(&data[p..end])?;
1394 pos = end;
1395 let (t, p) = tags::decode_tag(data, pos)?;
1397 let end = p + t.length as usize;
1398 if end > data.len() {
1399 return Err(Error::decoding(
1400 p,
1401 "SignedOutOfRange: truncated exceeded_limit",
1402 ));
1403 }
1404 let exceeded_limit = primitives::decode_signed(&data[p..end])?;
1405 let _ = (pos, end);
1406 Ok(Self::SignedOutOfRange {
1407 exceeding_value,
1408 status_flags,
1409 deadband,
1410 exceeded_limit,
1411 })
1412 }
1413 16 => {
1415 let mut pos = inner_start;
1416 let (t, p) = tags::decode_tag(data, pos)?;
1418 let end = p + t.length as usize;
1419 if end > data.len() {
1420 return Err(Error::decoding(
1421 p,
1422 "UnsignedOutOfRange: truncated exceeding_value",
1423 ));
1424 }
1425 let exceeding_value = primitives::decode_unsigned(&data[p..end])?;
1426 pos = end;
1427 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1429 let sf_end = sf_pos + sf_tag.length as usize;
1430 if sf_end > data.len() {
1431 return Err(Error::decoding(
1432 sf_pos,
1433 "UnsignedOutOfRange: truncated flags",
1434 ));
1435 }
1436 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1437 pos = sf_end;
1438 let (t, p) = tags::decode_tag(data, pos)?;
1440 let end = p + t.length as usize;
1441 if end > data.len() {
1442 return Err(Error::decoding(p, "UnsignedOutOfRange: truncated deadband"));
1443 }
1444 let deadband = primitives::decode_unsigned(&data[p..end])?;
1445 pos = end;
1446 let (t, p) = tags::decode_tag(data, pos)?;
1448 let end = p + t.length as usize;
1449 if end > data.len() {
1450 return Err(Error::decoding(
1451 p,
1452 "UnsignedOutOfRange: truncated exceeded_limit",
1453 ));
1454 }
1455 let exceeded_limit = primitives::decode_unsigned(&data[p..end])?;
1456 let _ = (pos, end);
1457 Ok(Self::UnsignedOutOfRange {
1458 exceeding_value,
1459 status_flags,
1460 deadband,
1461 exceeded_limit,
1462 })
1463 }
1464 17 => {
1466 let mut pos = inner_start;
1467 let (opt_data, new_pos) = tags::decode_optional_context(data, pos, 0)?;
1469 let changed_value = match opt_data {
1470 Some(content) => primitives::decode_character_string(content)?,
1471 None => {
1472 return Err(Error::decoding(
1473 pos,
1474 "ChangeOfCharacterstring: missing changed_value",
1475 ))
1476 }
1477 };
1478 pos = new_pos;
1479 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1481 let sf_end = sf_pos + sf_tag.length as usize;
1482 if sf_end > data.len() {
1483 return Err(Error::decoding(
1484 sf_pos,
1485 "ChangeOfCharacterstring: truncated flags",
1486 ));
1487 }
1488 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1489 pos = sf_end;
1490 let (opt_data, _new_pos) = tags::decode_optional_context(data, pos, 2)?;
1492 let alarm_value = match opt_data {
1493 Some(content) => primitives::decode_character_string(content)?,
1494 None => {
1495 return Err(Error::decoding(
1496 pos,
1497 "ChangeOfCharacterstring: missing alarm_value",
1498 ))
1499 }
1500 };
1501 Ok(Self::ChangeOfCharacterstring {
1502 changed_value,
1503 status_flags,
1504 alarm_value,
1505 })
1506 }
1507 18 => {
1509 let mut pos = inner_start;
1510 let (t, p) = tags::decode_tag(data, pos)?;
1512 if !t.is_opening || t.number != 0 {
1513 return Err(Error::decoding(
1514 pos,
1515 "ChangeOfStatusFlags: expected opening [0]",
1516 ));
1517 }
1518 let (present_value, after) = extract_raw_context(data, p, 0)?;
1519 pos = after;
1520 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1522 let sf_end = sf_pos + sf_tag.length as usize;
1523 if sf_end > data.len() {
1524 return Err(Error::decoding(
1525 sf_pos,
1526 "ChangeOfStatusFlags: truncated flags",
1527 ));
1528 }
1529 let referenced_flags = decode_status_flags(&data[sf_pos..sf_end]);
1530 Ok(Self::ChangeOfStatusFlags {
1531 present_value,
1532 referenced_flags,
1533 })
1534 }
1535 19 => {
1537 let mut pos = inner_start;
1538 let (t, p) = tags::decode_tag(data, pos)?;
1540 let end = p + t.length as usize;
1541 if end > data.len() {
1542 return Err(Error::decoding(
1543 p,
1544 "ChangeOfReliability: truncated reliability",
1545 ));
1546 }
1547 let reliability = primitives::decode_unsigned(&data[p..end])? as u32;
1548 pos = end;
1549 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1551 let sf_end = sf_pos + sf_tag.length as usize;
1552 if sf_end > data.len() {
1553 return Err(Error::decoding(
1554 sf_pos,
1555 "ChangeOfReliability: truncated flags",
1556 ));
1557 }
1558 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1559 pos = sf_end;
1560 let (t, p) = tags::decode_tag(data, pos)?;
1562 if !t.is_opening || t.number != 2 {
1563 return Err(Error::decoding(
1564 pos,
1565 "ChangeOfReliability: expected opening [2]",
1566 ));
1567 }
1568 let (property_values, _after) = extract_raw_context(data, p, 2)?;
1569 Ok(Self::ChangeOfReliability {
1570 reliability,
1571 status_flags,
1572 property_values,
1573 })
1574 }
1575 20 => Ok(Self::NoneParams),
1577 21 => {
1579 let mut pos = inner_start;
1580 let (t, p) = tags::decode_tag(data, pos)?;
1582 if !t.is_opening || t.number != 0 {
1583 return Err(Error::decoding(
1584 pos,
1585 "ChangeOfDiscreteValue: expected opening [0]",
1586 ));
1587 }
1588 let (new_value, after) = extract_raw_context(data, p, 0)?;
1589 pos = after;
1590 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1592 let sf_end = sf_pos + sf_tag.length as usize;
1593 if sf_end > data.len() {
1594 return Err(Error::decoding(
1595 sf_pos,
1596 "ChangeOfDiscreteValue: truncated flags",
1597 ));
1598 }
1599 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1600 Ok(Self::ChangeOfDiscreteValue {
1601 new_value,
1602 status_flags,
1603 })
1604 }
1605 22 => {
1607 let mut pos = inner_start;
1608 let (t, p) = tags::decode_tag(data, pos)?;
1610 let end = p + t.length as usize;
1611 if end > data.len() {
1612 return Err(Error::decoding(p, "ChangeOfTimer: truncated new_state"));
1613 }
1614 let new_state = primitives::decode_unsigned(&data[p..end])? as u32;
1615 pos = end;
1616 let (sf_tag, sf_pos) = tags::decode_tag(data, pos)?;
1618 let sf_end = sf_pos + sf_tag.length as usize;
1619 if sf_end > data.len() {
1620 return Err(Error::decoding(sf_pos, "ChangeOfTimer: truncated flags"));
1621 }
1622 let status_flags = decode_status_flags(&data[sf_pos..sf_end]);
1623 pos = sf_end;
1624 let (t, p) = tags::decode_tag(data, pos)?;
1626 if !t.is_opening || t.number != 2 {
1627 return Err(Error::decoding(
1628 pos,
1629 "ChangeOfTimer: expected opening [2] for update-time",
1630 ));
1631 }
1632 pos = p;
1633 let (d_tag, d_pos) = tags::decode_tag(data, pos)?;
1635 let d_end = d_pos + d_tag.length as usize;
1636 if d_end > data.len() {
1637 return Err(Error::decoding(
1638 d_pos,
1639 "ChangeOfTimer: truncated update date",
1640 ));
1641 }
1642 let update_date = Date::decode(&data[d_pos..d_end])?;
1643 pos = d_end;
1644 let (t_tag, t_pos) = tags::decode_tag(data, pos)?;
1646 let t_end = t_pos + t_tag.length as usize;
1647 if t_end > data.len() {
1648 return Err(Error::decoding(
1649 t_pos,
1650 "ChangeOfTimer: truncated update time",
1651 ));
1652 }
1653 let update_time_val = Time::decode(&data[t_pos..t_end])?;
1654 pos = t_end;
1655 let (ct, cp) = tags::decode_tag(data, pos)?;
1657 if !ct.is_closing || ct.number != 2 {
1658 return Err(Error::decoding(pos, "ChangeOfTimer: expected closing [2]"));
1659 }
1660 pos = cp;
1661 let update_time = (update_date, update_time_val);
1662 let (t, p) = tags::decode_tag(data, pos)?;
1664 let end = p + t.length as usize;
1665 if end > data.len() {
1666 return Err(Error::decoding(
1667 p,
1668 "ChangeOfTimer: truncated last_state_change",
1669 ));
1670 }
1671 let last_state_change = primitives::decode_unsigned(&data[p..end])? as u32;
1672 pos = end;
1673 let (t, p) = tags::decode_tag(data, pos)?;
1675 let end = p + t.length as usize;
1676 if end > data.len() {
1677 return Err(Error::decoding(
1678 p,
1679 "ChangeOfTimer: truncated initial_timeout",
1680 ));
1681 }
1682 let initial_timeout = primitives::decode_unsigned(&data[p..end])? as u32;
1683 pos = end;
1684 let (t, p) = tags::decode_tag(data, pos)?;
1686 if !t.is_opening || t.number != 5 {
1687 return Err(Error::decoding(
1688 pos,
1689 "ChangeOfTimer: expected opening [5] for expiration-time",
1690 ));
1691 }
1692 pos = p;
1693 let (d_tag, d_pos) = tags::decode_tag(data, pos)?;
1694 let d_end = d_pos + d_tag.length as usize;
1695 if d_end > data.len() {
1696 return Err(Error::decoding(
1697 d_pos,
1698 "ChangeOfTimer: truncated expiration date",
1699 ));
1700 }
1701 let exp_date = Date::decode(&data[d_pos..d_end])?;
1702 pos = d_end;
1703 let (t_tag, t_pos) = tags::decode_tag(data, pos)?;
1704 let t_end = t_pos + t_tag.length as usize;
1705 if t_end > data.len() {
1706 return Err(Error::decoding(
1707 t_pos,
1708 "ChangeOfTimer: truncated expiration time",
1709 ));
1710 }
1711 let exp_time = Time::decode(&data[t_pos..t_end])?;
1712 let _ = (pos, t_end);
1713 let expiration_time = (exp_date, exp_time);
1714 Ok(Self::ChangeOfTimer {
1715 new_state,
1716 status_flags,
1717 update_time,
1718 last_state_change,
1719 initial_timeout,
1720 expiration_time,
1721 })
1722 }
1723 other => Err(Error::decoding(
1724 offset,
1725 format!("NotificationParameters variant [{other}] unknown"),
1726 )),
1727 }
1728 }
1729}
1730
1731fn encode_property_states(buf: &mut BytesMut, state: &BACnetPropertyStates) {
1733 match state {
1734 BACnetPropertyStates::BooleanValue(v) => {
1735 primitives::encode_ctx_boolean(buf, 0, *v);
1736 }
1737 BACnetPropertyStates::BinaryValue(v) => {
1738 primitives::encode_ctx_unsigned(buf, 1, *v as u64);
1739 }
1740 BACnetPropertyStates::EventType(v) => {
1741 primitives::encode_ctx_unsigned(buf, 2, *v as u64);
1742 }
1743 BACnetPropertyStates::Polarity(v) => {
1744 primitives::encode_ctx_unsigned(buf, 3, *v as u64);
1745 }
1746 BACnetPropertyStates::ProgramChange(v) => {
1747 primitives::encode_ctx_unsigned(buf, 4, *v as u64);
1748 }
1749 BACnetPropertyStates::ProgramState(v) => {
1750 primitives::encode_ctx_unsigned(buf, 5, *v as u64);
1751 }
1752 BACnetPropertyStates::ReasonForHalt(v) => {
1753 primitives::encode_ctx_unsigned(buf, 6, *v as u64);
1754 }
1755 BACnetPropertyStates::Reliability(v) => {
1756 primitives::encode_ctx_unsigned(buf, 7, *v as u64);
1757 }
1758 BACnetPropertyStates::State(v) => {
1759 primitives::encode_ctx_unsigned(buf, 8, *v as u64);
1760 }
1761 BACnetPropertyStates::SystemStatus(v) => {
1762 primitives::encode_ctx_unsigned(buf, 9, *v as u64);
1763 }
1764 BACnetPropertyStates::Units(v) => {
1765 primitives::encode_ctx_unsigned(buf, 10, *v as u64);
1766 }
1767 BACnetPropertyStates::LifeSafetyMode(v) => {
1768 primitives::encode_ctx_unsigned(buf, 12, *v as u64);
1769 }
1770 BACnetPropertyStates::LifeSafetyState(v) => {
1771 primitives::encode_ctx_unsigned(buf, 13, *v as u64);
1772 }
1773 BACnetPropertyStates::Other { tag, data } => {
1774 primitives::encode_ctx_octet_string(buf, *tag, data);
1775 }
1776 }
1777}
1778
1779fn decode_property_states(data: &[u8], pos: &mut usize) -> Result<BACnetPropertyStates, Error> {
1781 let (tag, content_start) = tags::decode_tag(data, *pos)?;
1782 let end = content_start + tag.length as usize;
1783 if end > data.len() {
1784 return Err(Error::decoding(
1785 content_start,
1786 "BACnetPropertyStates: truncated",
1787 ));
1788 }
1789 let content = &data[content_start..end];
1790 *pos = end;
1791 match tag.number {
1792 0 => Ok(BACnetPropertyStates::BooleanValue(
1793 !content.is_empty() && content[0] != 0,
1794 )),
1795 1 => Ok(BACnetPropertyStates::BinaryValue(
1796 primitives::decode_unsigned(content)? as u32,
1797 )),
1798 2 => Ok(BACnetPropertyStates::EventType(
1799 primitives::decode_unsigned(content)? as u32,
1800 )),
1801 3 => Ok(BACnetPropertyStates::Polarity(
1802 primitives::decode_unsigned(content)? as u32,
1803 )),
1804 4 => Ok(BACnetPropertyStates::ProgramChange(
1805 primitives::decode_unsigned(content)? as u32,
1806 )),
1807 5 => Ok(BACnetPropertyStates::ProgramState(
1808 primitives::decode_unsigned(content)? as u32,
1809 )),
1810 6 => Ok(BACnetPropertyStates::ReasonForHalt(
1811 primitives::decode_unsigned(content)? as u32,
1812 )),
1813 7 => Ok(BACnetPropertyStates::Reliability(
1814 primitives::decode_unsigned(content)? as u32,
1815 )),
1816 8 => Ok(BACnetPropertyStates::State(
1817 primitives::decode_unsigned(content)? as u32,
1818 )),
1819 9 => Ok(BACnetPropertyStates::SystemStatus(
1820 primitives::decode_unsigned(content)? as u32,
1821 )),
1822 10 => Ok(BACnetPropertyStates::Units(
1823 primitives::decode_unsigned(content)? as u32,
1824 )),
1825 12 => Ok(BACnetPropertyStates::LifeSafetyMode(
1826 primitives::decode_unsigned(content)? as u32,
1827 )),
1828 13 => Ok(BACnetPropertyStates::LifeSafetyState(
1829 primitives::decode_unsigned(content)? as u32,
1830 )),
1831 n => Ok(BACnetPropertyStates::Other {
1832 tag: n,
1833 data: content.to_vec(),
1834 }),
1835 }
1836}
1837
1838fn decode_device_obj_prop_ref(
1841 data: &[u8],
1842 pos: &mut usize,
1843) -> Result<BACnetDeviceObjectPropertyReference, Error> {
1844 let (t, p) = tags::decode_tag(data, *pos)?;
1846 let end = p + t.length as usize;
1847 if end > data.len() {
1848 return Err(Error::decoding(
1849 p,
1850 "DeviceObjectPropertyRef: truncated objectIdentifier",
1851 ));
1852 }
1853 let object_identifier = ObjectIdentifier::decode(&data[p..end])?;
1854 *pos = end;
1855
1856 let (t, p) = tags::decode_tag(data, *pos)?;
1858 let end = p + t.length as usize;
1859 if end > data.len() {
1860 return Err(Error::decoding(
1861 p,
1862 "DeviceObjectPropertyRef: truncated propertyIdentifier",
1863 ));
1864 }
1865 let property_identifier = primitives::decode_unsigned(&data[p..end])? as u32;
1866 *pos = end;
1867
1868 let mut property_array_index = None;
1870 if *pos < data.len() {
1871 let (peek, peek_pos) = tags::decode_tag(data, *pos)?;
1872 if peek.is_context(2) {
1873 let end = peek_pos + peek.length as usize;
1874 if end > data.len() {
1875 return Err(Error::decoding(
1876 peek_pos,
1877 "DeviceObjectPropertyRef: truncated propertyArrayIndex",
1878 ));
1879 }
1880 property_array_index = Some(primitives::decode_unsigned(&data[peek_pos..end])? as u32);
1881 *pos = end;
1882 }
1883 }
1884
1885 let mut device_identifier = None;
1887 if *pos < data.len() {
1888 let (peek, peek_pos) = tags::decode_tag(data, *pos)?;
1889 if peek.is_context(3) {
1890 let end = peek_pos + peek.length as usize;
1891 if end > data.len() {
1892 return Err(Error::decoding(
1893 peek_pos,
1894 "DeviceObjectPropertyRef: truncated deviceIdentifier",
1895 ));
1896 }
1897 device_identifier = Some(ObjectIdentifier::decode(&data[peek_pos..end])?);
1898 *pos = end;
1899 }
1900 }
1901
1902 Ok(BACnetDeviceObjectPropertyReference {
1903 object_identifier,
1904 property_identifier,
1905 property_array_index,
1906 device_identifier,
1907 })
1908}
1909
1910fn extract_raw_context(
1916 data: &[u8],
1917 start: usize,
1918 tag_number: u8,
1919) -> Result<(Vec<u8>, usize), Error> {
1920 let open_byte = (tag_number << 4) | 0x0E;
1923 let close_byte = (tag_number << 4) | 0x0F;
1924 let mut depth: usize = 1;
1925 let mut pos = start;
1926 while pos < data.len() {
1927 let b = data[pos];
1928 if b == open_byte {
1929 depth += 1;
1930 } else if b == close_byte {
1931 depth -= 1;
1932 if depth == 0 {
1933 let raw = data[start..pos].to_vec();
1934 return Ok((raw, pos + 1)); }
1936 }
1937 pos += 1;
1938 }
1939 Err(Error::decoding(
1940 start,
1941 format!("extract_raw_context: missing closing tag [{tag_number}]"),
1942 ))
1943}
1944
1945fn decode_status_flags(data: &[u8]) -> u8 {
1948 if data.len() >= 2 {
1950 let unused = data[0];
1951 data[1] >> (unused.min(7))
1952 } else {
1953 0
1954 }
1955}
1956
1957#[derive(Debug, Clone, PartialEq, Eq)]
1963pub struct GetEventInformationRequest {
1964 pub last_received_object_identifier: Option<ObjectIdentifier>,
1965}
1966
1967impl GetEventInformationRequest {
1968 pub fn encode(&self, buf: &mut BytesMut) {
1969 if let Some(ref oid) = self.last_received_object_identifier {
1970 primitives::encode_ctx_object_id(buf, 0, oid);
1971 }
1972 }
1973
1974 pub fn decode(data: &[u8]) -> Result<Self, Error> {
1975 if data.is_empty() {
1976 return Ok(Self {
1977 last_received_object_identifier: None,
1978 });
1979 }
1980 let (opt_data, _) = tags::decode_optional_context(data, 0, 0)?;
1981 let last_received_object_identifier = if let Some(content) = opt_data {
1982 Some(ObjectIdentifier::decode(content)?)
1983 } else {
1984 None
1985 };
1986 Ok(Self {
1987 last_received_object_identifier,
1988 })
1989 }
1990}
1991
1992#[derive(Debug, Clone)]
1994pub struct GetEventInformationAck {
1995 pub list_of_event_summaries: Vec<EventSummary>,
1996 pub more_events: bool,
1997}
1998
1999#[derive(Debug, Clone)]
2001pub struct EventSummary {
2002 pub object_identifier: ObjectIdentifier,
2003 pub event_state: u32,
2004 pub acknowledged_transitions: u8,
2006 pub event_timestamps: [BACnetTimeStamp; 3],
2008 pub notify_type: u32,
2010 pub event_enable: u8,
2012 pub event_priorities: [u32; 3],
2014 pub notification_class: u32,
2015}
2016
2017impl GetEventInformationAck {
2018 pub fn decode(data: &[u8]) -> Result<Self, Error> {
2020 let mut offset = 0;
2021
2022 let (tag, pos) = tags::decode_tag(data, offset)?;
2024 if !tag.is_opening_tag(0) {
2025 return Err(Error::decoding(offset, "expected opening tag [0]"));
2026 }
2027 offset = pos;
2028
2029 let mut list_of_event_summaries = Vec::new();
2030
2031 loop {
2033 let (tag, _) = tags::decode_tag(data, offset)?;
2034 if tag.is_closing_tag(0) {
2035 let (_, close_pos) = tags::decode_tag(data, offset)?;
2037 offset = close_pos;
2038 break;
2039 }
2040
2041 let (tag, pos) = tags::decode_tag(data, offset)?;
2043 let end = pos + tag.length as usize;
2044 if end > data.len() {
2045 return Err(Error::decoding(pos, "GetEventInfoAck truncated at oid"));
2046 }
2047 let object_identifier = ObjectIdentifier::decode(&data[pos..end])?;
2048 offset = end;
2049
2050 let (tag, pos) = tags::decode_tag(data, offset)?;
2052 let end = pos + tag.length as usize;
2053 if end > data.len() {
2054 return Err(Error::decoding(
2055 pos,
2056 "GetEventInfoAck truncated at eventState",
2057 ));
2058 }
2059 let event_state = primitives::decode_unsigned(&data[pos..end])? as u32;
2060 offset = end;
2061
2062 let (tag, pos) = tags::decode_tag(data, offset)?;
2064 let end = pos + tag.length as usize;
2065 if end > data.len() {
2066 return Err(Error::decoding(pos, "truncated at ackedTransitions"));
2067 }
2068 let acknowledged_transitions = if end > pos + 1 { data[pos + 1] >> 5 } else { 0 };
2070 offset = end;
2071
2072 let (tag, pos) = tags::decode_tag(data, offset)?;
2074 if !tag.is_opening_tag(3) {
2075 return Err(Error::decoding(offset, "expected opening tag [3]"));
2076 }
2077 offset = pos;
2078 let mut event_timestamps = [
2079 BACnetTimeStamp::SequenceNumber(0),
2080 BACnetTimeStamp::SequenceNumber(0),
2081 BACnetTimeStamp::SequenceNumber(0),
2082 ];
2083 for ts in &mut event_timestamps {
2084 let (inner_tag, inner_pos) = tags::decode_tag(data, offset)?;
2085 if inner_tag.is_opening_tag(0) {
2086 offset = inner_pos;
2088 let (app_tag, app_pos) = tags::decode_tag(data, offset)?;
2089 let end = app_pos + app_tag.length as usize;
2090 if end > data.len() {
2091 return Err(Error::decoding(app_pos, "truncated timestamp time"));
2092 }
2093 *ts = BACnetTimeStamp::Time(Time::decode(&data[app_pos..end])?);
2094 offset = end;
2095 let (_, close_pos) = tags::decode_tag(data, offset)?;
2097 offset = close_pos;
2098 } else if inner_tag.is_context(1) {
2099 let end = inner_pos + inner_tag.length as usize;
2101 if end > data.len() {
2102 return Err(Error::decoding(inner_pos, "truncated timestamp seqnum"));
2103 }
2104 *ts = BACnetTimeStamp::SequenceNumber(primitives::decode_unsigned(
2105 &data[inner_pos..end],
2106 )?);
2107 offset = end;
2108 } else if inner_tag.is_opening_tag(2) {
2109 offset = inner_pos;
2111 let (d_tag, d_pos) = tags::decode_tag(data, offset)?;
2112 let d_end = d_pos + d_tag.length as usize;
2113 if d_end > data.len() {
2114 return Err(Error::decoding(d_pos, "truncated datetime date"));
2115 }
2116 let date = Date::decode(&data[d_pos..d_end])?;
2117 offset = d_end;
2118 let (t_tag, t_pos) = tags::decode_tag(data, offset)?;
2119 let t_end = t_pos + t_tag.length as usize;
2120 if t_end > data.len() {
2121 return Err(Error::decoding(t_pos, "truncated datetime time"));
2122 }
2123 let time = Time::decode(&data[t_pos..t_end])?;
2124 offset = t_end;
2125 *ts = BACnetTimeStamp::DateTime { date, time };
2126 let (_, close_pos) = tags::decode_tag(data, offset)?;
2128 offset = close_pos;
2129 } else {
2130 return Err(Error::decoding(offset, "unexpected timestamp choice"));
2131 }
2132 }
2133 let (tag, _) = tags::decode_tag(data, offset)?;
2135 if !tag.is_closing_tag(3) {
2136 return Err(Error::decoding(offset, "expected closing tag [3]"));
2137 }
2138 let (_, close_pos) = tags::decode_tag(data, offset)?;
2139 offset = close_pos;
2140
2141 let (tag, pos) = tags::decode_tag(data, offset)?;
2143 let end = pos + tag.length as usize;
2144 if end > data.len() {
2145 return Err(Error::decoding(pos, "truncated at notifyType"));
2146 }
2147 let notify_type = primitives::decode_unsigned(&data[pos..end])? as u32;
2148 offset = end;
2149
2150 let (tag, pos) = tags::decode_tag(data, offset)?;
2152 let end = pos + tag.length as usize;
2153 if end > data.len() {
2154 return Err(Error::decoding(pos, "truncated at eventEnable"));
2155 }
2156 let event_enable = if end > pos + 1 { data[pos + 1] >> 5 } else { 0 };
2157 offset = end;
2158
2159 let (tag, pos) = tags::decode_tag(data, offset)?;
2161 if !tag.is_opening_tag(6) {
2162 return Err(Error::decoding(offset, "expected opening tag [6]"));
2163 }
2164 offset = pos;
2165 let mut event_priorities = [0u32; 3];
2166 for pri in &mut event_priorities {
2167 let (tag, pos) = tags::decode_tag(data, offset)?;
2168 let end = pos + tag.length as usize;
2169 if end > data.len() {
2170 return Err(Error::decoding(pos, "truncated priority"));
2171 }
2172 *pri = primitives::decode_unsigned(&data[pos..end])? as u32;
2173 offset = end;
2174 }
2175 let (tag, _) = tags::decode_tag(data, offset)?;
2177 if !tag.is_closing_tag(6) {
2178 return Err(Error::decoding(offset, "expected closing tag [6]"));
2179 }
2180 let (_, close_pos) = tags::decode_tag(data, offset)?;
2181 offset = close_pos;
2182
2183 list_of_event_summaries.push(EventSummary {
2184 object_identifier,
2185 event_state,
2186 acknowledged_transitions,
2187 event_timestamps,
2188 notify_type,
2189 event_enable,
2190 event_priorities,
2191 notification_class: 0, });
2193 }
2194
2195 let (tag, pos) = tags::decode_tag(data, offset)?;
2197 let end = pos + tag.length as usize;
2198 if end > data.len() {
2199 return Err(Error::decoding(pos, "truncated at moreEvents"));
2200 }
2201 let more_events = data[pos] != 0;
2202
2203 Ok(Self {
2204 list_of_event_summaries,
2205 more_events,
2206 })
2207 }
2208
2209 pub fn encode(&self, buf: &mut BytesMut) {
2210 tags::encode_opening_tag(buf, 0);
2212 for summary in &self.list_of_event_summaries {
2213 primitives::encode_ctx_object_id(buf, 0, &summary.object_identifier);
2215 primitives::encode_ctx_enumerated(buf, 1, summary.event_state);
2217 primitives::encode_ctx_bit_string(buf, 2, 5, &[summary.acknowledged_transitions << 5]);
2219 tags::encode_opening_tag(buf, 3);
2221 for ts in &summary.event_timestamps {
2222 match ts {
2225 BACnetTimeStamp::Time(t) => {
2226 tags::encode_opening_tag(buf, 0);
2227 primitives::encode_app_time(buf, t);
2228 tags::encode_closing_tag(buf, 0);
2229 }
2230 BACnetTimeStamp::SequenceNumber(n) => {
2231 primitives::encode_ctx_unsigned(buf, 1, *n);
2232 }
2233 BACnetTimeStamp::DateTime { date, time } => {
2234 tags::encode_opening_tag(buf, 2);
2235 primitives::encode_app_date(buf, date);
2236 primitives::encode_app_time(buf, time);
2237 tags::encode_closing_tag(buf, 2);
2238 }
2239 }
2240 }
2241 tags::encode_closing_tag(buf, 3);
2242 primitives::encode_ctx_enumerated(buf, 4, summary.notify_type);
2244 primitives::encode_ctx_bit_string(buf, 5, 5, &[summary.event_enable << 5]);
2246 tags::encode_opening_tag(buf, 6);
2248 for &p in &summary.event_priorities {
2249 primitives::encode_app_unsigned(buf, p as u64);
2250 }
2251 tags::encode_closing_tag(buf, 6);
2252 }
2253 tags::encode_closing_tag(buf, 0);
2254 primitives::encode_ctx_boolean(buf, 1, self.more_events);
2256 }
2257}
2258
2259#[cfg(test)]
2260mod tests {
2261 use super::*;
2262 use bacnet_types::enums::ObjectType;
2263
2264 #[test]
2265 fn acknowledge_alarm_round_trip() {
2266 let req = AcknowledgeAlarmRequest {
2267 acknowledging_process_identifier: 1,
2268 event_object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap(),
2269 event_state_acknowledged: 3, timestamp: BACnetTimeStamp::SequenceNumber(42),
2271 acknowledgment_source: "operator".into(),
2272 };
2273 let mut buf = BytesMut::new();
2274 req.encode(&mut buf).unwrap();
2275 let decoded = AcknowledgeAlarmRequest::decode(&buf).unwrap();
2276 assert_eq!(decoded.acknowledging_process_identifier, 1);
2277 assert_eq!(decoded.event_object_identifier, req.event_object_identifier);
2278 assert_eq!(decoded.event_state_acknowledged, 3);
2279 assert_eq!(decoded.timestamp, BACnetTimeStamp::SequenceNumber(42));
2280 assert_eq!(decoded.acknowledgment_source, "operator");
2281 }
2282
2283 #[test]
2284 fn get_event_info_empty_request() {
2285 let req = GetEventInformationRequest {
2286 last_received_object_identifier: None,
2287 };
2288 let mut buf = BytesMut::new();
2289 req.encode(&mut buf);
2290 let decoded = GetEventInformationRequest::decode(&buf).unwrap();
2291 assert!(decoded.last_received_object_identifier.is_none());
2292 }
2293
2294 #[test]
2295 fn get_event_info_with_last_received() {
2296 let oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 5).unwrap();
2297 let req = GetEventInformationRequest {
2298 last_received_object_identifier: Some(oid),
2299 };
2300 let mut buf = BytesMut::new();
2301 req.encode(&mut buf);
2302 let decoded = GetEventInformationRequest::decode(&buf).unwrap();
2303 assert_eq!(decoded.last_received_object_identifier, Some(oid));
2304 }
2305
2306 #[test]
2307 fn event_notification_round_trip() {
2308 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2309 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2310
2311 let req = EventNotificationRequest {
2312 process_identifier: 1,
2313 initiating_device_identifier: device_oid,
2314 event_object_identifier: ai_oid,
2315 timestamp: BACnetTimeStamp::SequenceNumber(7),
2316 notification_class: 5,
2317 priority: 100,
2318 event_type: 5, notify_type: 0, ack_required: true,
2321 from_state: 0, to_state: 3, event_values: None,
2324 };
2325 let mut buf = BytesMut::new();
2326 req.encode(&mut buf).unwrap();
2327
2328 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2329 assert_eq!(decoded.process_identifier, 1);
2330 assert_eq!(decoded.initiating_device_identifier, device_oid);
2331 assert_eq!(decoded.event_object_identifier, ai_oid);
2332 assert_eq!(decoded.timestamp, BACnetTimeStamp::SequenceNumber(7));
2333 assert_eq!(decoded.notification_class, 5);
2334 assert_eq!(decoded.priority, 100);
2335 assert_eq!(decoded.event_type, 5);
2336 assert_eq!(decoded.notify_type, 0);
2337 assert!(decoded.ack_required);
2338 assert_eq!(decoded.from_state, 0);
2339 assert_eq!(decoded.to_state, 3);
2340 assert!(decoded.event_values.is_none());
2341 }
2342
2343 #[test]
2344 fn event_notification_datetime_timestamp_round_trip() {
2345 use bacnet_types::primitives::{Date, Time};
2346
2347 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2348 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2349
2350 let ts = BACnetTimeStamp::DateTime {
2351 date: Date {
2352 year: 126,
2353 month: 2,
2354 day: 28,
2355 day_of_week: 6,
2356 },
2357 time: Time {
2358 hour: 14,
2359 minute: 30,
2360 second: 0,
2361 hundredths: 0,
2362 },
2363 };
2364
2365 let req = EventNotificationRequest {
2366 process_identifier: 1,
2367 initiating_device_identifier: device_oid,
2368 event_object_identifier: ai_oid,
2369 timestamp: ts.clone(),
2370 notification_class: 5,
2371 priority: 100,
2372 event_type: 5,
2373 notify_type: 0,
2374 ack_required: true,
2375 from_state: 0,
2376 to_state: 3,
2377 event_values: None,
2378 };
2379 let mut buf = BytesMut::new();
2380 req.encode(&mut buf).unwrap();
2381
2382 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2383 assert_eq!(decoded.timestamp, ts);
2384 }
2385
2386 #[test]
2387 fn event_notification_time_timestamp_round_trip() {
2388 use bacnet_types::primitives::Time;
2389
2390 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2391 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2392
2393 let ts = BACnetTimeStamp::Time(Time {
2394 hour: 10,
2395 minute: 15,
2396 second: 30,
2397 hundredths: 50,
2398 });
2399
2400 let req = EventNotificationRequest {
2401 process_identifier: 1,
2402 initiating_device_identifier: device_oid,
2403 event_object_identifier: ai_oid,
2404 timestamp: ts.clone(),
2405 notification_class: 5,
2406 priority: 100,
2407 event_type: 5,
2408 notify_type: 0,
2409 ack_required: true,
2410 from_state: 0,
2411 to_state: 3,
2412 event_values: None,
2413 };
2414 let mut buf = BytesMut::new();
2415 req.encode(&mut buf).unwrap();
2416
2417 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2418 assert_eq!(decoded.timestamp, ts);
2419 }
2420
2421 #[test]
2426 fn test_decode_acknowledge_alarm_empty_input() {
2427 assert!(AcknowledgeAlarmRequest::decode(&[]).is_err());
2428 }
2429
2430 #[test]
2431 fn test_decode_acknowledge_alarm_truncated_1_byte() {
2432 let req = AcknowledgeAlarmRequest {
2433 acknowledging_process_identifier: 1,
2434 event_object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap(),
2435 event_state_acknowledged: 3,
2436 timestamp: BACnetTimeStamp::SequenceNumber(42),
2437 acknowledgment_source: "operator".into(),
2438 };
2439 let mut buf = BytesMut::new();
2440 req.encode(&mut buf).unwrap();
2441 assert!(AcknowledgeAlarmRequest::decode(&buf[..1]).is_err());
2442 }
2443
2444 #[test]
2445 fn test_decode_acknowledge_alarm_truncated_3_bytes() {
2446 let req = AcknowledgeAlarmRequest {
2447 acknowledging_process_identifier: 1,
2448 event_object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap(),
2449 event_state_acknowledged: 3,
2450 timestamp: BACnetTimeStamp::SequenceNumber(42),
2451 acknowledgment_source: "operator".into(),
2452 };
2453 let mut buf = BytesMut::new();
2454 req.encode(&mut buf).unwrap();
2455 assert!(AcknowledgeAlarmRequest::decode(&buf[..3]).is_err());
2456 }
2457
2458 #[test]
2459 fn test_decode_acknowledge_alarm_truncated_half() {
2460 let req = AcknowledgeAlarmRequest {
2461 acknowledging_process_identifier: 1,
2462 event_object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap(),
2463 event_state_acknowledged: 3,
2464 timestamp: BACnetTimeStamp::SequenceNumber(42),
2465 acknowledgment_source: "operator".into(),
2466 };
2467 let mut buf = BytesMut::new();
2468 req.encode(&mut buf).unwrap();
2469 let half = buf.len() / 2;
2470 assert!(AcknowledgeAlarmRequest::decode(&buf[..half]).is_err());
2471 }
2472
2473 #[test]
2474 fn test_decode_acknowledge_alarm_invalid_tag() {
2475 assert!(AcknowledgeAlarmRequest::decode(&[0xFF, 0xFF, 0xFF]).is_err());
2476 }
2477
2478 #[test]
2479 fn test_decode_event_notification_empty_input() {
2480 assert!(EventNotificationRequest::decode(&[]).is_err());
2481 }
2482
2483 #[test]
2484 fn test_decode_event_notification_truncated_1_byte() {
2485 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2486 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2487 let req = EventNotificationRequest {
2488 process_identifier: 1,
2489 initiating_device_identifier: device_oid,
2490 event_object_identifier: ai_oid,
2491 timestamp: BACnetTimeStamp::SequenceNumber(7),
2492 notification_class: 5,
2493 priority: 100,
2494 event_type: 5,
2495 notify_type: 0,
2496 ack_required: true,
2497 from_state: 0,
2498 to_state: 3,
2499 event_values: None,
2500 };
2501 let mut buf = BytesMut::new();
2502 req.encode(&mut buf).unwrap();
2503 assert!(EventNotificationRequest::decode(&buf[..1]).is_err());
2504 }
2505
2506 #[test]
2507 fn test_decode_event_notification_truncated_3_bytes() {
2508 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2509 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2510 let req = EventNotificationRequest {
2511 process_identifier: 1,
2512 initiating_device_identifier: device_oid,
2513 event_object_identifier: ai_oid,
2514 timestamp: BACnetTimeStamp::SequenceNumber(7),
2515 notification_class: 5,
2516 priority: 100,
2517 event_type: 5,
2518 notify_type: 0,
2519 ack_required: true,
2520 from_state: 0,
2521 to_state: 3,
2522 event_values: None,
2523 };
2524 let mut buf = BytesMut::new();
2525 req.encode(&mut buf).unwrap();
2526 assert!(EventNotificationRequest::decode(&buf[..3]).is_err());
2527 }
2528
2529 #[test]
2530 fn test_decode_event_notification_truncated_half() {
2531 let device_oid = ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap();
2532 let ai_oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap();
2533 let req = EventNotificationRequest {
2534 process_identifier: 1,
2535 initiating_device_identifier: device_oid,
2536 event_object_identifier: ai_oid,
2537 timestamp: BACnetTimeStamp::SequenceNumber(7),
2538 notification_class: 5,
2539 priority: 100,
2540 event_type: 5,
2541 notify_type: 0,
2542 ack_required: true,
2543 from_state: 0,
2544 to_state: 3,
2545 event_values: None,
2546 };
2547 let mut buf = BytesMut::new();
2548 req.encode(&mut buf).unwrap();
2549 let half = buf.len() / 2;
2550 assert!(EventNotificationRequest::decode(&buf[..half]).is_err());
2551 }
2552
2553 #[test]
2554 fn test_decode_event_notification_invalid_tag() {
2555 assert!(EventNotificationRequest::decode(&[0xFF, 0xFF, 0xFF]).is_err());
2556 }
2557
2558 #[test]
2559 fn test_decode_get_event_info_invalid_tag() {
2560 let result = GetEventInformationRequest::decode(&[0xFF, 0xFF]).unwrap();
2562 assert!(result.last_received_object_identifier.is_none());
2563 }
2564
2565 #[test]
2566 fn test_decode_get_event_info_truncated() {
2567 let oid = ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 5).unwrap();
2568 let req = GetEventInformationRequest {
2569 last_received_object_identifier: Some(oid),
2570 };
2571 let mut buf = BytesMut::new();
2572 req.encode(&mut buf);
2573 assert!(GetEventInformationRequest::decode(&buf[..1]).is_err());
2574 }
2575
2576 fn make_event_req(event_values: Option<NotificationParameters>) -> EventNotificationRequest {
2582 EventNotificationRequest {
2583 process_identifier: 1,
2584 initiating_device_identifier: ObjectIdentifier::new(ObjectType::DEVICE, 1).unwrap(),
2585 event_object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 3).unwrap(),
2586 timestamp: BACnetTimeStamp::SequenceNumber(7),
2587 notification_class: 5,
2588 priority: 100,
2589 event_type: 5,
2590 notify_type: 0,
2591 ack_required: true,
2592 from_state: 0,
2593 to_state: 3,
2594 event_values,
2595 }
2596 }
2597
2598 #[test]
2599 fn notification_params_out_of_range_round_trip() {
2600 let params = NotificationParameters::OutOfRange {
2601 exceeding_value: 85.5,
2602 status_flags: 0b1000, deadband: 1.0,
2604 exceeded_limit: 80.0,
2605 };
2606 let req = make_event_req(Some(params));
2607 let mut buf = BytesMut::new();
2608 req.encode(&mut buf).unwrap();
2609 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2610 let ev = decoded.event_values.unwrap();
2611 match ev {
2612 NotificationParameters::OutOfRange {
2613 exceeding_value,
2614 status_flags,
2615 deadband,
2616 exceeded_limit,
2617 } => {
2618 assert_eq!(exceeding_value, 85.5);
2619 assert_eq!(status_flags, 0b1000);
2620 assert_eq!(deadband, 1.0);
2621 assert_eq!(exceeded_limit, 80.0);
2622 }
2623 other => panic!("expected OutOfRange, got {:?}", other),
2624 }
2625 }
2626
2627 #[test]
2628 fn notification_params_change_of_state_boolean_round_trip() {
2629 let params = NotificationParameters::ChangeOfState {
2630 new_state: BACnetPropertyStates::BooleanValue(true),
2631 status_flags: 0b1100, };
2633 let req = make_event_req(Some(params));
2634 let mut buf = BytesMut::new();
2635 req.encode(&mut buf).unwrap();
2636 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2637 let ev = decoded.event_values.unwrap();
2638 match ev {
2639 NotificationParameters::ChangeOfState {
2640 new_state,
2641 status_flags,
2642 } => {
2643 assert_eq!(new_state, BACnetPropertyStates::BooleanValue(true));
2644 assert_eq!(status_flags, 0b1100);
2645 }
2646 other => panic!("expected ChangeOfState, got {:?}", other),
2647 }
2648 }
2649
2650 #[test]
2651 fn notification_params_change_of_state_enumerated_round_trip() {
2652 let params = NotificationParameters::ChangeOfState {
2653 new_state: BACnetPropertyStates::State(3), status_flags: 0b1000,
2655 };
2656 let req = make_event_req(Some(params));
2657 let mut buf = BytesMut::new();
2658 req.encode(&mut buf).unwrap();
2659 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2660 let ev = decoded.event_values.unwrap();
2661 match ev {
2662 NotificationParameters::ChangeOfState {
2663 new_state,
2664 status_flags,
2665 } => {
2666 assert_eq!(new_state, BACnetPropertyStates::State(3));
2667 assert_eq!(status_flags, 0b1000);
2668 }
2669 other => panic!("expected ChangeOfState, got {:?}", other),
2670 }
2671 }
2672
2673 #[test]
2674 fn notification_params_change_of_value_real_round_trip() {
2675 let params = NotificationParameters::ChangeOfValue {
2676 new_value: ChangeOfValueChoice::ChangedValue(72.5),
2677 status_flags: 0b0100,
2678 };
2679 let req = make_event_req(Some(params));
2680 let mut buf = BytesMut::new();
2681 req.encode(&mut buf).unwrap();
2682 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2683 let ev = decoded.event_values.unwrap();
2684 match ev {
2685 NotificationParameters::ChangeOfValue {
2686 new_value,
2687 status_flags,
2688 } => {
2689 assert_eq!(new_value, ChangeOfValueChoice::ChangedValue(72.5));
2690 assert_eq!(status_flags, 0b0100);
2691 }
2692 other => panic!("expected ChangeOfValue, got {:?}", other),
2693 }
2694 }
2695
2696 #[test]
2697 fn notification_params_buffer_ready_round_trip() {
2698 let buffer_prop = BACnetDeviceObjectPropertyReference::new_local(
2699 ObjectIdentifier::new(ObjectType::TREND_LOG, 1).unwrap(),
2700 131, );
2702 let params = NotificationParameters::BufferReady {
2703 buffer_property: buffer_prop.clone(),
2704 previous_notification: 10,
2705 current_notification: 20,
2706 };
2707 let req = make_event_req(Some(params));
2708 let mut buf = BytesMut::new();
2709 req.encode(&mut buf).unwrap();
2710 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2711 let ev = decoded.event_values.unwrap();
2712 match ev {
2713 NotificationParameters::BufferReady {
2714 buffer_property,
2715 previous_notification,
2716 current_notification,
2717 } => {
2718 assert_eq!(buffer_property, buffer_prop);
2719 assert_eq!(previous_notification, 10);
2720 assert_eq!(current_notification, 20);
2721 }
2722 other => panic!("expected BufferReady, got {:?}", other),
2723 }
2724 }
2725
2726 #[test]
2727 fn notification_params_none_round_trip() {
2728 let params = NotificationParameters::NoneParams;
2729 let req = make_event_req(Some(params));
2730 let mut buf = BytesMut::new();
2731 req.encode(&mut buf).unwrap();
2732 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2733 assert_eq!(
2734 decoded.event_values,
2735 Some(NotificationParameters::NoneParams)
2736 );
2737 }
2738
2739 #[test]
2740 fn notification_params_unsigned_range_round_trip() {
2741 let params = NotificationParameters::UnsignedRange {
2742 exceeding_value: 500,
2743 status_flags: 0b1000,
2744 exceeded_limit: 400,
2745 };
2746 let req = make_event_req(Some(params));
2747 let mut buf = BytesMut::new();
2748 req.encode(&mut buf).unwrap();
2749 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2750 let ev = decoded.event_values.unwrap();
2751 match ev {
2752 NotificationParameters::UnsignedRange {
2753 exceeding_value,
2754 status_flags,
2755 exceeded_limit,
2756 } => {
2757 assert_eq!(exceeding_value, 500);
2758 assert_eq!(status_flags, 0b1000);
2759 assert_eq!(exceeded_limit, 400);
2760 }
2761 other => panic!("expected UnsignedRange, got {:?}", other),
2762 }
2763 }
2764
2765 #[test]
2766 fn event_notification_no_event_values_backward_compatible() {
2767 let req = make_event_req(None);
2769 let mut buf = BytesMut::new();
2770 req.encode(&mut buf).unwrap();
2771 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2772 assert!(decoded.event_values.is_none());
2773 assert_eq!(decoded.process_identifier, 1);
2774 assert_eq!(decoded.to_state, 3);
2775 }
2776
2777 #[test]
2778 fn get_event_information_ack_round_trip() {
2779 let ack = GetEventInformationAck {
2780 list_of_event_summaries: vec![EventSummary {
2781 object_identifier: ObjectIdentifier::new(ObjectType::ANALOG_INPUT, 1).unwrap(),
2782 event_state: 3,
2783 acknowledged_transitions: 0b101,
2784 event_timestamps: [
2785 BACnetTimeStamp::SequenceNumber(42),
2786 BACnetTimeStamp::SequenceNumber(0),
2787 BACnetTimeStamp::SequenceNumber(100),
2788 ],
2789 notify_type: 0,
2790 event_enable: 0b111,
2791 event_priorities: [3, 3, 3],
2792 notification_class: 0,
2793 }],
2794 more_events: true,
2795 };
2796 let mut buf = BytesMut::new();
2797 ack.encode(&mut buf);
2798 let decoded = GetEventInformationAck::decode(&buf).unwrap();
2799 assert_eq!(decoded.list_of_event_summaries.len(), 1);
2800 assert!(decoded.more_events);
2801 let s = &decoded.list_of_event_summaries[0];
2802 assert_eq!(
2803 s.object_identifier,
2804 ack.list_of_event_summaries[0].object_identifier
2805 );
2806 assert_eq!(s.event_state, 3);
2807 assert_eq!(s.acknowledged_transitions, 0b101);
2808 assert_eq!(s.event_timestamps[0], BACnetTimeStamp::SequenceNumber(42));
2809 assert_eq!(s.notify_type, 0);
2810 assert_eq!(s.event_enable, 0b111);
2811 assert_eq!(s.event_priorities, [3, 3, 3]);
2812 }
2813
2814 #[test]
2815 fn notification_params_change_of_bitstring_round_trip() {
2816 let params = NotificationParameters::ChangeOfBitstring {
2817 referenced_bitstring: (2, vec![0xA0]),
2818 status_flags: 0b1000,
2819 };
2820 let req = make_event_req(Some(params));
2821 let mut buf = BytesMut::new();
2822 req.encode(&mut buf).unwrap();
2823 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2824 let ev = decoded.event_values.unwrap();
2825 match ev {
2826 NotificationParameters::ChangeOfBitstring {
2827 referenced_bitstring,
2828 status_flags,
2829 } => {
2830 assert_eq!(referenced_bitstring, (2, vec![0xA0]));
2831 assert_eq!(status_flags, 0b1000);
2832 }
2833 other => panic!("expected ChangeOfBitstring, got {:?}", other),
2834 }
2835 }
2836
2837 #[test]
2838 fn notification_params_command_failure_round_trip() {
2839 let params = NotificationParameters::CommandFailure {
2840 command_value: vec![0x91, 0x01],
2841 status_flags: 0b1100,
2842 feedback_value: vec![0x91, 0x02],
2843 };
2844 let req = make_event_req(Some(params));
2845 let mut buf = BytesMut::new();
2846 req.encode(&mut buf).unwrap();
2847 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2848 let ev = decoded.event_values.unwrap();
2849 match ev {
2850 NotificationParameters::CommandFailure {
2851 command_value,
2852 status_flags,
2853 feedback_value,
2854 } => {
2855 assert_eq!(command_value, vec![0x91, 0x01]);
2856 assert_eq!(status_flags, 0b1100);
2857 assert_eq!(feedback_value, vec![0x91, 0x02]);
2858 }
2859 other => panic!("expected CommandFailure, got {:?}", other),
2860 }
2861 }
2862
2863 #[test]
2864 fn notification_params_floating_limit_round_trip() {
2865 let params = NotificationParameters::FloatingLimit {
2866 reference_value: 50.0,
2867 status_flags: 0b1000,
2868 setpoint_value: 45.0,
2869 error_limit: 2.0,
2870 };
2871 let req = make_event_req(Some(params));
2872 let mut buf = BytesMut::new();
2873 req.encode(&mut buf).unwrap();
2874 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2875 let ev = decoded.event_values.unwrap();
2876 match ev {
2877 NotificationParameters::FloatingLimit {
2878 reference_value,
2879 status_flags,
2880 setpoint_value,
2881 error_limit,
2882 } => {
2883 assert_eq!(reference_value, 50.0);
2884 assert_eq!(status_flags, 0b1000);
2885 assert_eq!(setpoint_value, 45.0);
2886 assert_eq!(error_limit, 2.0);
2887 }
2888 other => panic!("expected FloatingLimit, got {:?}", other),
2889 }
2890 }
2891
2892 #[test]
2893 fn notification_params_change_of_life_safety_round_trip() {
2894 let params = NotificationParameters::ChangeOfLifeSafety {
2895 new_state: 3,
2896 new_mode: 1,
2897 status_flags: 0b1000,
2898 operation_expected: 2,
2899 };
2900 let req = make_event_req(Some(params));
2901 let mut buf = BytesMut::new();
2902 req.encode(&mut buf).unwrap();
2903 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2904 let ev = decoded.event_values.unwrap();
2905 match ev {
2906 NotificationParameters::ChangeOfLifeSafety {
2907 new_state,
2908 new_mode,
2909 status_flags,
2910 operation_expected,
2911 } => {
2912 assert_eq!(new_state, 3);
2913 assert_eq!(new_mode, 1);
2914 assert_eq!(status_flags, 0b1000);
2915 assert_eq!(operation_expected, 2);
2916 }
2917 other => panic!("expected ChangeOfLifeSafety, got {:?}", other),
2918 }
2919 }
2920
2921 #[test]
2922 fn notification_params_extended_round_trip() {
2923 let params = NotificationParameters::Extended {
2924 vendor_id: 42,
2925 extended_event_type: 7,
2926 parameters: vec![0x01, 0x02, 0x03],
2927 };
2928 let req = make_event_req(Some(params));
2929 let mut buf = BytesMut::new();
2930 req.encode(&mut buf).unwrap();
2931 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2932 let ev = decoded.event_values.unwrap();
2933 match ev {
2934 NotificationParameters::Extended {
2935 vendor_id,
2936 extended_event_type,
2937 parameters,
2938 } => {
2939 assert_eq!(vendor_id, 42);
2940 assert_eq!(extended_event_type, 7);
2941 assert_eq!(parameters, vec![0x01, 0x02, 0x03]);
2942 }
2943 other => panic!("expected Extended, got {:?}", other),
2944 }
2945 }
2946
2947 #[test]
2948 fn notification_params_access_event_round_trip() {
2949 use bacnet_types::primitives::{Date, Time};
2950
2951 let cred = BACnetDeviceObjectPropertyReference::new_local(
2952 ObjectIdentifier::new(ObjectType::ACCESS_CREDENTIAL, 1).unwrap(),
2953 85, );
2955 let params = NotificationParameters::AccessEvent {
2956 access_event: 5,
2957 status_flags: 0b1000,
2958 access_event_tag: 10,
2959 access_event_time: (
2960 Date {
2961 year: 124,
2962 month: 6,
2963 day: 15,
2964 day_of_week: 3,
2965 },
2966 Time {
2967 hour: 10,
2968 minute: 30,
2969 second: 0,
2970 hundredths: 0,
2971 },
2972 ),
2973 access_credential: cred.clone(),
2974 authentication_factor: vec![0xAB, 0xCD],
2975 };
2976 let req = make_event_req(Some(params));
2977 let mut buf = BytesMut::new();
2978 req.encode(&mut buf).unwrap();
2979 let decoded = EventNotificationRequest::decode(&buf).unwrap();
2980 let ev = decoded.event_values.unwrap();
2981 match ev {
2982 NotificationParameters::AccessEvent {
2983 access_event,
2984 status_flags,
2985 access_event_tag,
2986 access_event_time,
2987 access_credential,
2988 authentication_factor,
2989 } => {
2990 assert_eq!(access_event, 5);
2991 assert_eq!(status_flags, 0b1000);
2992 assert_eq!(access_event_tag, 10);
2993 assert_eq!(access_event_time.0.year, 124);
2994 assert_eq!(access_event_time.1.hour, 10);
2995 assert_eq!(access_credential, cred);
2996 assert_eq!(authentication_factor, vec![0xAB, 0xCD]);
2997 }
2998 other => panic!("expected AccessEvent, got {:?}", other),
2999 }
3000 }
3001
3002 #[test]
3003 fn notification_params_double_out_of_range_round_trip() {
3004 let params = NotificationParameters::DoubleOutOfRange {
3005 exceeding_value: 100.5,
3006 status_flags: 0b1000,
3007 deadband: 0.5,
3008 exceeded_limit: 100.0,
3009 };
3010 let req = make_event_req(Some(params));
3011 let mut buf = BytesMut::new();
3012 req.encode(&mut buf).unwrap();
3013 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3014 let ev = decoded.event_values.unwrap();
3015 match ev {
3016 NotificationParameters::DoubleOutOfRange {
3017 exceeding_value,
3018 status_flags,
3019 deadband,
3020 exceeded_limit,
3021 } => {
3022 assert_eq!(exceeding_value, 100.5);
3023 assert_eq!(status_flags, 0b1000);
3024 assert_eq!(deadband, 0.5);
3025 assert_eq!(exceeded_limit, 100.0);
3026 }
3027 other => panic!("expected DoubleOutOfRange, got {:?}", other),
3028 }
3029 }
3030
3031 #[test]
3032 fn notification_params_signed_out_of_range_round_trip() {
3033 let params = NotificationParameters::SignedOutOfRange {
3034 exceeding_value: -10,
3035 status_flags: 0b1000,
3036 deadband: 5,
3037 exceeded_limit: -5,
3038 };
3039 let req = make_event_req(Some(params));
3040 let mut buf = BytesMut::new();
3041 req.encode(&mut buf).unwrap();
3042 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3043 let ev = decoded.event_values.unwrap();
3044 match ev {
3045 NotificationParameters::SignedOutOfRange {
3046 exceeding_value,
3047 status_flags,
3048 deadband,
3049 exceeded_limit,
3050 } => {
3051 assert_eq!(exceeding_value, -10);
3052 assert_eq!(status_flags, 0b1000);
3053 assert_eq!(deadband, 5);
3054 assert_eq!(exceeded_limit, -5);
3055 }
3056 other => panic!("expected SignedOutOfRange, got {:?}", other),
3057 }
3058 }
3059
3060 #[test]
3061 fn notification_params_unsigned_out_of_range_round_trip() {
3062 let params = NotificationParameters::UnsignedOutOfRange {
3063 exceeding_value: 200,
3064 status_flags: 0b1000,
3065 deadband: 10,
3066 exceeded_limit: 190,
3067 };
3068 let req = make_event_req(Some(params));
3069 let mut buf = BytesMut::new();
3070 req.encode(&mut buf).unwrap();
3071 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3072 let ev = decoded.event_values.unwrap();
3073 match ev {
3074 NotificationParameters::UnsignedOutOfRange {
3075 exceeding_value,
3076 status_flags,
3077 deadband,
3078 exceeded_limit,
3079 } => {
3080 assert_eq!(exceeding_value, 200);
3081 assert_eq!(status_flags, 0b1000);
3082 assert_eq!(deadband, 10);
3083 assert_eq!(exceeded_limit, 190);
3084 }
3085 other => panic!("expected UnsignedOutOfRange, got {:?}", other),
3086 }
3087 }
3088
3089 #[test]
3090 fn notification_params_change_of_characterstring_round_trip() {
3091 let params = NotificationParameters::ChangeOfCharacterstring {
3092 changed_value: "hello".to_string(),
3093 status_flags: 0b1000,
3094 alarm_value: "alarm".to_string(),
3095 };
3096 let req = make_event_req(Some(params));
3097 let mut buf = BytesMut::new();
3098 req.encode(&mut buf).unwrap();
3099 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3100 let ev = decoded.event_values.unwrap();
3101 match ev {
3102 NotificationParameters::ChangeOfCharacterstring {
3103 changed_value,
3104 status_flags,
3105 alarm_value,
3106 } => {
3107 assert_eq!(changed_value, "hello");
3108 assert_eq!(status_flags, 0b1000);
3109 assert_eq!(alarm_value, "alarm");
3110 }
3111 other => panic!("expected ChangeOfCharacterstring, got {:?}", other),
3112 }
3113 }
3114
3115 #[test]
3116 fn notification_params_change_of_status_flags_round_trip() {
3117 let params = NotificationParameters::ChangeOfStatusFlags {
3118 present_value: vec![0x91, 0x03],
3119 referenced_flags: 0b1010,
3120 };
3121 let req = make_event_req(Some(params));
3122 let mut buf = BytesMut::new();
3123 req.encode(&mut buf).unwrap();
3124 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3125 let ev = decoded.event_values.unwrap();
3126 match ev {
3127 NotificationParameters::ChangeOfStatusFlags {
3128 present_value,
3129 referenced_flags,
3130 } => {
3131 assert_eq!(present_value, vec![0x91, 0x03]);
3132 assert_eq!(referenced_flags, 0b1010);
3133 }
3134 other => panic!("expected ChangeOfStatusFlags, got {:?}", other),
3135 }
3136 }
3137
3138 #[test]
3139 fn notification_params_change_of_reliability_round_trip() {
3140 let params = NotificationParameters::ChangeOfReliability {
3141 reliability: 7,
3142 status_flags: 0b0100,
3143 property_values: vec![0x01, 0x02],
3144 };
3145 let req = make_event_req(Some(params));
3146 let mut buf = BytesMut::new();
3147 req.encode(&mut buf).unwrap();
3148 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3149 let ev = decoded.event_values.unwrap();
3150 match ev {
3151 NotificationParameters::ChangeOfReliability {
3152 reliability,
3153 status_flags,
3154 property_values,
3155 } => {
3156 assert_eq!(reliability, 7);
3157 assert_eq!(status_flags, 0b0100);
3158 assert_eq!(property_values, vec![0x01, 0x02]);
3159 }
3160 other => panic!("expected ChangeOfReliability, got {:?}", other),
3161 }
3162 }
3163
3164 #[test]
3165 fn notification_params_change_of_discrete_value_round_trip() {
3166 let params = NotificationParameters::ChangeOfDiscreteValue {
3167 new_value: vec![0x91, 0x05],
3168 status_flags: 0b1000,
3169 };
3170 let req = make_event_req(Some(params));
3171 let mut buf = BytesMut::new();
3172 req.encode(&mut buf).unwrap();
3173 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3174 let ev = decoded.event_values.unwrap();
3175 match ev {
3176 NotificationParameters::ChangeOfDiscreteValue {
3177 new_value,
3178 status_flags,
3179 } => {
3180 assert_eq!(new_value, vec![0x91, 0x05]);
3181 assert_eq!(status_flags, 0b1000);
3182 }
3183 other => panic!("expected ChangeOfDiscreteValue, got {:?}", other),
3184 }
3185 }
3186
3187 #[test]
3188 fn notification_params_change_of_timer_round_trip() {
3189 use bacnet_types::primitives::{Date, Time};
3190
3191 let params = NotificationParameters::ChangeOfTimer {
3192 new_state: 1,
3193 status_flags: 0b1000,
3194 update_time: (
3195 Date {
3196 year: 124,
3197 month: 3,
3198 day: 10,
3199 day_of_week: 1,
3200 },
3201 Time {
3202 hour: 8,
3203 minute: 0,
3204 second: 0,
3205 hundredths: 0,
3206 },
3207 ),
3208 last_state_change: 0,
3209 initial_timeout: 300,
3210 expiration_time: (
3211 Date {
3212 year: 124,
3213 month: 3,
3214 day: 10,
3215 day_of_week: 1,
3216 },
3217 Time {
3218 hour: 8,
3219 minute: 5,
3220 second: 0,
3221 hundredths: 0,
3222 },
3223 ),
3224 };
3225 let req = make_event_req(Some(params));
3226 let mut buf = BytesMut::new();
3227 req.encode(&mut buf).unwrap();
3228 let decoded = EventNotificationRequest::decode(&buf).unwrap();
3229 let ev = decoded.event_values.unwrap();
3230 match ev {
3231 NotificationParameters::ChangeOfTimer {
3232 new_state,
3233 status_flags,
3234 update_time,
3235 last_state_change,
3236 initial_timeout,
3237 expiration_time,
3238 } => {
3239 assert_eq!(new_state, 1);
3240 assert_eq!(status_flags, 0b1000);
3241 assert_eq!(update_time.0.year, 124);
3242 assert_eq!(update_time.1.hour, 8);
3243 assert_eq!(last_state_change, 0);
3244 assert_eq!(initial_timeout, 300);
3245 assert_eq!(expiration_time.0.year, 124);
3246 assert_eq!(expiration_time.1.minute, 5);
3247 }
3248 other => panic!("expected ChangeOfTimer, got {:?}", other),
3249 }
3250 }
3251
3252 #[test]
3253 fn get_event_information_ack_empty_list() {
3254 let ack = GetEventInformationAck {
3255 list_of_event_summaries: vec![],
3256 more_events: false,
3257 };
3258 let mut buf = BytesMut::new();
3259 ack.encode(&mut buf);
3260 let decoded = GetEventInformationAck::decode(&buf).unwrap();
3261 assert!(decoded.list_of_event_summaries.is_empty());
3262 assert!(!decoded.more_events);
3263 }
3264}