use super::*;
use bacnet_encoding::constructed::tagged::{
decode_app_unsigned, decode_ctx_boolean, decode_ctx_object_id, decode_ctx_primitive,
decode_ctx_unsigned, expect_end, misplaced_tag, unclosed_kind,
};
use bacnet_types::bitstring::EventTransitionBits;
fn decode_event_transition_bits(
data: &[u8],
offset: usize,
expected_tag: u8,
field: &str,
) -> Result<(EventTransitionBits, usize), Error> {
let (content, end) = decode_ctx_primitive(data, offset, expected_tag, field)?;
if content.len() != 2 || content[0] != 5 || content[1] & 0x1f != 0 {
return Err(Error::decoding(
offset,
format!("{field} must contain three bits with zero padding"),
));
}
Ok((EventTransitionBits::from_bacnet(&content[1..]), end))
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct GetEventInformationRequest {
pub last_received_object_identifier: Option<ObjectIdentifier>,
}
impl GetEventInformationRequest {
pub fn encode(&self, buf: &mut BytesMut) {
if let Some(ref oid) = self.last_received_object_identifier {
primitives::encode_ctx_object_id(buf, 0, oid);
}
}
pub fn decode(data: &[u8]) -> Result<Self, Error> {
if data.is_empty() {
return Ok(Self {
last_received_object_identifier: None,
});
}
let (object_identifier, end) = decode_ctx_object_id(
data,
0,
0,
"GetEventInformation last-received-object-identifier",
)?;
expect_end(data, end, end, "GetEventInformation")?;
Ok(Self {
last_received_object_identifier: Some(object_identifier),
})
}
}
#[derive(Debug, Clone)]
pub struct GetEventInformationAck {
pub list_of_event_summaries: Vec<EventSummary>,
pub more_events: bool,
}
#[derive(Debug, Clone)]
pub struct EventSummary {
pub object_identifier: ObjectIdentifier,
pub event_state: EventState,
pub acknowledged_transitions: EventTransitionBits,
pub event_timestamps: [BACnetTimeStamp; 3],
pub notify_type: NotifyType,
pub event_enable: EventTransitionBits,
pub event_priorities: [u32; 3],
}
impl GetEventInformationAck {
pub fn decode(data: &[u8]) -> Result<Self, Error> {
let (tag, mut offset) = tags::decode_tag(data, 0)?;
if !tag.is_opening_tag(0) {
return Err(misplaced_tag(
data,
&tag,
Some(0),
0,
"GetEventInformation ACK expected opening tag 0",
));
}
let mut list_of_event_summaries = Vec::new();
loop {
let (tag, next) = tags::decode_tag(data, offset)?;
if tag.is_closing_tag(0) {
offset = next;
break;
}
if list_of_event_summaries.len() >= MAX_DECODED_ITEMS {
return Err(Error::overflow(
offset,
format!("GetEventInformation ACK exceeds {MAX_DECODED_ITEMS} event summaries"),
));
}
let (object_identifier, end) =
decode_ctx_object_id(data, offset, 0, "GetEventInformation ACK object-identifier")?;
offset = end;
let (event_state, end) =
decode_ctx_unsigned::<u32>(data, offset, 1, "GetEventInformation ACK event-state")?;
let event_state = EventState::from_raw(event_state);
offset = end;
let (acknowledged_transitions, end) = decode_event_transition_bits(
data,
offset,
2,
"GetEventInformation ACK acknowledged-transitions",
)?;
offset = end;
let (tag, next) = tags::decode_tag(data, offset)?;
if !tag.is_opening_tag(3) {
return Err(misplaced_tag(
data,
&tag,
Some(3),
offset,
"GetEventInformation ACK expected opening tag 3 for event-timestamps",
));
}
offset = next;
let mut event_timestamps = [
BACnetTimeStamp::SequenceNumber(0),
BACnetTimeStamp::SequenceNumber(0),
BACnetTimeStamp::SequenceNumber(0),
];
for ts in &mut event_timestamps {
let (decoded_ts, new_offset) = primitives::decode_timestamp_choice(data, offset)?;
*ts = decoded_ts;
offset = new_offset;
}
let (tag, next) = tags::decode_tag(data, offset)?;
if !tag.is_closing_tag(3) {
return Err(Error::decoding_kind(
unclosed_kind(&tag),
offset,
"GetEventInformation ACK expected closing tag 3 for event-timestamps",
));
}
offset = next;
let (notify_type, end) =
decode_ctx_unsigned::<u32>(data, offset, 4, "GetEventInformation ACK notify-type")?;
let notify_type = NotifyType::from_raw(notify_type);
offset = end;
let (event_enable, end) = decode_event_transition_bits(
data,
offset,
5,
"GetEventInformation ACK event-enable",
)?;
offset = end;
let (tag, next) = tags::decode_tag(data, offset)?;
if !tag.is_opening_tag(6) {
return Err(misplaced_tag(
data,
&tag,
Some(6),
offset,
"GetEventInformation ACK expected opening tag 6 for event-priorities",
));
}
offset = next;
let mut event_priorities = [0u32; 3];
for pri in &mut event_priorities {
let (value, end) = decode_app_unsigned::<u32>(
data,
offset,
"GetEventInformation ACK event-priority",
)?;
*pri = value;
offset = end;
}
let (tag, next) = tags::decode_tag(data, offset)?;
if !tag.is_closing_tag(6) {
return Err(Error::decoding_kind(
unclosed_kind(&tag),
offset,
"GetEventInformation ACK expected closing tag 6 for event-priorities",
));
}
offset = next;
list_of_event_summaries.push(EventSummary {
object_identifier,
event_state,
acknowledged_transitions,
event_timestamps,
notify_type,
event_enable,
event_priorities,
});
}
let (more_events, end) =
decode_ctx_boolean(data, offset, 1, "GetEventInformation ACK more-events")?;
expect_end(data, end, end, "GetEventInformation ACK")?;
Ok(Self {
list_of_event_summaries,
more_events,
})
}
pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
tags::encode_opening_tag(buf, 0);
for summary in &self.list_of_event_summaries {
primitives::encode_ctx_object_id(buf, 0, &summary.object_identifier);
primitives::encode_ctx_enumerated(buf, 1, summary.event_state.to_raw());
primitives::encode_ctx_bit_string(
buf,
2,
5,
&[summary.acknowledged_transitions.to_bacnet()],
);
tags::encode_opening_tag(buf, 3);
for ts in &summary.event_timestamps {
primitives::encode_timestamp_choice(buf, ts)?;
}
tags::encode_closing_tag(buf, 3);
primitives::encode_ctx_enumerated(buf, 4, summary.notify_type.to_raw());
primitives::encode_ctx_bit_string(buf, 5, 5, &[summary.event_enable.to_bacnet()]);
tags::encode_opening_tag(buf, 6);
for &p in &summary.event_priorities {
primitives::encode_app_unsigned(buf, p as u64);
}
tags::encode_closing_tag(buf, 6);
}
tags::encode_closing_tag(buf, 0);
primitives::encode_ctx_boolean(buf, 1, self.more_events);
Ok(())
}
}