use bacnet_types::constructed::BACnetObjectPropertyReference;
use bacnet_types::enums::{BinaryPV, ObjectType, PropertyIdentifier};
use bacnet_types::primitives::{ObjectIdentifier, PropertyValue};
use super::ObjectDatabase;
impl ObjectDatabase {
pub fn follow_event_algorithm_inhibit(&mut self, oid: &ObjectIdentifier) -> bool {
let Some(reference) = self
.objects
.get(oid)
.and_then(|object| object.event_algorithm_inhibit_reference_internal())
else {
return false;
};
let inhibit = self.inhibit_value(&reference);
self.objects
.get_mut(oid)
.is_some_and(|object| object.follow_event_algorithm_inhibit_internal(inhibit))
}
fn inhibit_value(&self, reference: &BACnetObjectPropertyReference) -> bool {
let property = PropertyIdentifier::from_raw(reference.property_identifier);
let index = reference.property_array_index;
let target = reference.object_identifier;
let value = self
.get(&target)
.and_then(|object| object.read_property(property, index).ok());
match value {
Some(PropertyValue::Boolean(inhibit)) => inhibit,
Some(PropertyValue::Enumerated(raw)) => {
raw == BinaryPV::ACTIVE.to_raw()
&& holds_binary_pv(target.object_type(), property, index)
}
_ => false,
}
}
}
fn holds_binary_pv(
object_type: ObjectType,
property: PropertyIdentifier,
index: Option<u32>,
) -> bool {
use PropertyIdentifier as P;
let commanded = property == P::RELINQUISH_DEFAULT
|| (property == P::PRIORITY_ARRAY && index.is_some_and(|slot| slot > 0));
match object_type {
ObjectType::BINARY_INPUT => matches!(property, P::PRESENT_VALUE | P::ALARM_VALUE),
ObjectType::BINARY_OUTPUT => {
matches!(property, P::PRESENT_VALUE | P::FEEDBACK_VALUE) || commanded
}
ObjectType::BINARY_VALUE => {
matches!(property, P::PRESENT_VALUE | P::ALARM_VALUE) || commanded
}
ObjectType::ACCESS_CREDENTIAL => property == P::CREDENTIAL_STATUS,
_ => false,
}
}
#[cfg(test)]
#[path = "event_algorithm_inhibit_tests.rs"]
mod tests;