use super::*;
use bacnet_encoding::constructed::tagged::{
decode_ctx_boolean, decode_ctx_object_id, decode_ctx_primitive, decode_ctx_unsigned,
expect_end, misplaced_tag, next_is_context,
};
use bacnet_encoding::constructed::{encode_event_notification, validate_tlv_sequence};
use bytes::Bytes;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ForwardedEventNotification {
pub process_identifier: u32,
pub initiating_device_identifier: ObjectIdentifier,
pub event_object_identifier: ObjectIdentifier,
pub notification_class: u32,
pub priority: u8,
pub notify_type: NotifyType,
pub to_state: EventState,
tail: Bytes,
}
impl ForwardedEventNotification {
pub fn decode(data: &[u8]) -> Result<Self, Error> {
const WHAT: &str = "EventNotification";
validate_tlv_sequence(data, WHAT)?;
let (process_identifier, tail_start) =
decode_ctx_unsigned::<u32>(data, 0, 0, "EventNotification processIdentifier")?;
let (initiating_device_identifier, offset) = decode_ctx_object_id(
data,
tail_start,
1,
"EventNotification initiatingDeviceIdentifier",
)?;
let (event_object_identifier, offset) =
decode_ctx_object_id(data, offset, 2, "EventNotification eventObjectIdentifier")?;
let (_, offset) = primitives::decode_timestamp(data, offset, 3)?;
let (notification_class, offset) =
decode_ctx_unsigned::<u32>(data, offset, 4, "EventNotification notificationClass")?;
let (priority, offset) =
decode_ctx_unsigned::<u8>(data, offset, 5, "EventNotification priority")?;
let (_, mut offset) =
decode_ctx_unsigned::<u32>(data, offset, 6, "EventNotification eventType")?;
if next_is_context(data, offset, 7)? {
(_, offset) = decode_ctx_primitive(data, offset, 7, "EventNotification messageText")?;
}
let (notify_type, mut offset) =
decode_ctx_unsigned::<u32>(data, offset, 8, "EventNotification notifyType")?;
let notify_type = NotifyType::from_raw(notify_type);
if next_is_context(data, offset, 9)? {
(_, offset) = decode_ctx_boolean(data, offset, 9, "EventNotification ackRequired")?;
}
if next_is_context(data, offset, 10)? {
(_, offset) =
decode_ctx_unsigned::<u32>(data, offset, 10, "EventNotification fromState")?;
} else if notify_type != NotifyType::ACK_NOTIFICATION {
if offset < data.len() {
let (found, _) = tags::decode_tag(data, offset)?;
return Err(misplaced_tag(
data,
&found,
Some(10),
offset,
"EventNotification expected fromState",
));
}
return Err(Error::missing(
offset,
"EventNotification missing fromState",
));
}
let (to_state, offset) =
decode_ctx_unsigned::<u32>(data, offset, 11, "EventNotification toState")?;
let to_state = EventState::from_raw(to_state);
if offset < data.len() {
let (opening, inner) = tags::decode_tag(data, offset)?;
if !opening.is_opening_tag(12) {
return Err(misplaced_tag(
data,
&opening,
Some(12),
offset,
"EventNotification expected eventValues after toState",
));
}
let (values, end) = tags::extract_context_value(data, inner, 12)?;
if values.is_empty() {
return Err(Error::missing(
offset,
"EventNotification eventValues are empty",
));
}
expect_end(data, end, end, "EventNotification")?;
}
Ok(Self {
process_identifier,
initiating_device_identifier,
event_object_identifier,
notification_class,
priority,
notify_type,
to_state,
tail: Bytes::copy_from_slice(&data[tail_start..]),
})
}
pub fn from_request(request: &EventNotificationRequest) -> Result<Self, Error> {
let mut buf = BytesMut::new();
encode_event_notification(request, &mut buf)?;
Self::decode(&buf)
}
pub fn retargeted(&self, process_identifier: u32) -> Self {
Self {
process_identifier,
..self.clone()
}
}
pub fn encode_for(&self, process_identifier: u32) -> Bytes {
let mut buf = BytesMut::with_capacity(self.tail.len() + 6);
primitives::encode_ctx_unsigned(&mut buf, 0, u64::from(process_identifier));
buf.extend_from_slice(&self.tail);
buf.freeze()
}
}