use bacnet_encoding::primitives::encode_timestamp_choice;
use bacnet_types::constructed::BACnetDeviceObjectReference;
use bacnet_types::enums::{
AccessEvent, AccessUserType, AuthenticationStatus, BinaryPV, DoorAlarmState, DoorSecuredStatus,
DoorStatus, DoorValue, EventState, LockStatus, ObjectType, PropertyIdentifier, Reliability,
};
use bacnet_types::error::Error;
use bacnet_types::primitives::{
BACnetTimeStamp, Date, ObjectIdentifier, PropertyValue, StatusFlags, Time,
};
use bytes::BytesMut;
use std::borrow::Cow;
use std::sync::Arc;
use crate::clock::{current_datetime, ClockReader};
use crate::common::{self, read_common_properties};
use crate::traits::BACnetObject;
fn never_updated() -> BACnetTimeStamp {
BACnetTimeStamp::DateTime {
date: Date {
year: Date::UNSPECIFIED,
month: Date::UNSPECIFIED,
day: Date::UNSPECIFIED,
day_of_week: Date::UNSPECIFIED,
},
time: Time {
hour: Time::UNSPECIFIED,
minute: Time::UNSPECIFIED,
second: Time::UNSPECIFIED,
hundredths: Time::UNSPECIFIED,
},
}
}
fn timestamp_value(stamp: &BACnetTimeStamp) -> Result<PropertyValue, Error> {
let mut buf = BytesMut::new();
encode_timestamp_choice(&mut buf, stamp)?;
Ok(PropertyValue::ApplicationData(buf.to_vec()))
}
fn update_stamp(
clock: Option<&dyn ClockReader>,
sequence: impl FnOnce() -> u16,
) -> BACnetTimeStamp {
match current_datetime(clock) {
Some((date, time)) => BACnetTimeStamp::DateTime { date, time },
None => BACnetTimeStamp::SequenceNumber(sequence()),
}
}
fn next_sequence(previous: u16) -> u16 {
if previous == u16::MAX {
1
} else {
previous + 1
}
}
#[derive(Default)]
struct UpdateClock {
clock: Option<Arc<dyn ClockReader>>,
sequence: u16,
}
impl UpdateClock {
fn stamp(&mut self) -> BACnetTimeStamp {
let sequence = &mut self.sequence;
update_stamp(self.clock.as_deref(), || {
*sequence = next_sequence(*sequence);
*sequence
})
}
}
fn simulated_reliability(value: &PropertyValue) -> Result<Reliability, Error> {
let PropertyValue::Enumerated(raw) = value else {
return Err(common::invalid_data_type_error());
};
checked_reliability(Reliability::from_raw(*raw))
}
fn checked_reliability(reliability: Reliability) -> Result<Reliability, Error> {
if common::is_reliability_value_valid(reliability) {
Ok(reliability)
} else {
Err(common::value_out_of_range_error())
}
}
fn references_to(
object_type: ObjectType,
references: impl IntoIterator<Item = impl Into<BACnetDeviceObjectReference>>,
) -> Result<Vec<BACnetDeviceObjectReference>, Error> {
let references: Vec<BACnetDeviceObjectReference> =
references.into_iter().map(Into::into).collect();
for reference in &references {
crate::device_reference::check_device_member(reference.device_identifier)?;
if reference.object_identifier.object_type() != object_type {
return Err(common::value_out_of_range_error());
}
}
Ok(references)
}
mod credential;
mod credential_data_input;
mod credential_data_input_formats;
mod credential_data_input_out_of_service;
mod credential_rules;
mod door;
mod door_alarm;
mod door_out_of_service;
mod input;
mod metadata_identity;
mod metadata_topology;
mod point;
mod point_authorization;
mod point_event_time;
mod rights;
mod rights_evaluation;
mod rights_writes;
mod user;
mod zone;
mod zone_occupancy;
mod zone_out_of_service;
pub use credential::*;
pub use credential_data_input::*;
pub use door::*;
pub use input::*;
pub use point::*;
pub use rights::*;
pub use rights_evaluation::*;
pub use user::*;
pub use zone::*;
#[cfg(test)]
mod array_tests;
#[cfg(test)]
mod constructed_value_tests;
#[cfg(test)]
mod credential_data_input_format_tests;
#[cfg(test)]
mod credential_data_input_out_of_service_tests;
#[cfg(test)]
mod credential_exemption_tests;
#[cfg(test)]
mod credential_tests;
#[cfg(test)]
mod device_reference_tests;
#[cfg(test)]
mod door_alarm_tests;
#[cfg(test)]
mod door_out_of_service_tests;
#[cfg(test)]
mod door_pulse_tests;
#[cfg(test)]
mod input_tests;
#[cfg(test)]
mod point_authorization_tests;
#[cfg(test)]
mod point_out_of_service_tests;
#[cfg(test)]
mod point_policy_tests;
#[cfg(test)]
mod point_status_tests;
#[cfg(test)]
mod tests;
#[cfg(test)]
mod typed_value_tests;
#[cfg(test)]
mod user_references_tests;
#[cfg(test)]
mod zone_event_tests;
#[cfg(test)]
mod zone_occupancy_tests;
#[cfg(test)]
mod zone_out_of_service_tests;
#[cfg(test)]
mod zone_points_tests;