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