Skip to main content

bacnet_objects/access_control/
mod.rs

1//! Access Control objects (ASHRAE 135-2020 Clause 12).
2//!
3//! This module implements the seven BACnet access control object types:
4//! - AccessDoor (type 30)
5//! - AccessCredential (type 32)
6//! - AccessPoint (type 33)
7//! - AccessRights (type 34)
8//! - AccessUser (type 35)
9//! - AccessZone (type 36)
10//! - CredentialDataInput (type 37)
11//!
12//! [`evaluate_access_rights`] checks a credential against the Access Rights
13//! it is assigned, for the application to act on (#1331).
14
15use bacnet_encoding::primitives::encode_timestamp_choice;
16use bacnet_types::constructed::BACnetDeviceObjectReference;
17use bacnet_types::enums::{
18    AccessEvent, AccessUserType, AuthenticationStatus, BinaryPV, DoorAlarmState, DoorSecuredStatus,
19    DoorStatus, DoorValue, EventState, LockStatus, ObjectType, PropertyIdentifier, Reliability,
20};
21use bacnet_types::error::Error;
22use bacnet_types::primitives::{
23    BACnetTimeStamp, Date, ObjectIdentifier, PropertyValue, StatusFlags, Time,
24};
25use bytes::BytesMut;
26use std::borrow::Cow;
27use std::sync::Arc;
28
29use crate::clock::{current_datetime, ClockReader};
30use crate::common::{self, read_common_properties};
31use crate::traits::BACnetObject;
32
33/// The time stamp an Access Point's Access_Event_Time and a Credential Data
34/// Input's Update_Time hold before their first update: the date-and-time form
35/// with every octet unspecified (Clauses 12.31.29 and 12.36.11).
36fn never_updated() -> BACnetTimeStamp {
37    BACnetTimeStamp::DateTime {
38        date: Date {
39            year: Date::UNSPECIFIED,
40            month: Date::UNSPECIFIED,
41            day: Date::UNSPECIFIED,
42            day_of_week: Date::UNSPECIFIED,
43        },
44        time: Time {
45            hour: Time::UNSPECIFIED,
46            minute: Time::UNSPECIFIED,
47            second: Time::UNSPECIFIED,
48            hundredths: Time::UNSPECIFIED,
49        },
50    }
51}
52
53/// A `BACnetTimeStamp` property in its Clause 21 CHOICE form.
54fn timestamp_value(stamp: &BACnetTimeStamp) -> Result<PropertyValue, Error> {
55    let mut buf = BytesMut::new();
56    encode_timestamp_choice(&mut buf, stamp)?;
57    Ok(PropertyValue::ApplicationData(buf.to_vec()))
58}
59
60/// The BACnetTimeStamp (Clause 21.6) for an update recorded now: the Device
61/// clock's date and time, or `sequence()` in the sequence-number form when
62/// there is no usable clock.
63///
64/// Without a clock every date-and-time stamp would be the unspecified one,
65/// so successive updates would carry the same time and a subscriber watching
66/// that time (Table 13-1) would hear none of them. A sequence number moves on
67/// with each update instead; Clauses 12.31.29 and 12.36.11 both allow an
68/// update time in that form.
69fn update_stamp(
70    clock: Option<&dyn ClockReader>,
71    sequence: impl FnOnce() -> u16,
72) -> BACnetTimeStamp {
73    match current_datetime(clock) {
74        Some((date, time)) => BACnetTimeStamp::DateTime { date, time },
75        None => BACnetTimeStamp::SequenceNumber(sequence()),
76    }
77}
78
79/// The sequence number after `previous`: it climbs from 1 to 65535, the top
80/// of the production's range, and starts again at 1. It never takes 0,
81/// which marks an update time with no update yet (Clauses 12.31.29 and
82/// 12.36.11).
83fn next_sequence(previous: u16) -> u16 {
84    if previous == u16::MAX {
85        1
86    } else {
87        previous + 1
88    }
89}
90
91/// The Device clock an object stamps its update times from, and the
92/// sequence numbers it hands out, in order, while that clock gives no usable
93/// reading (`update_stamp`).
94#[derive(Default)]
95struct UpdateClock {
96    clock: Option<Arc<dyn ClockReader>>,
97    /// The last sequence number handed out; 0 before the first.
98    sequence: u16,
99}
100
101impl UpdateClock {
102    /// Stamp an update made now.
103    fn stamp(&mut self) -> BACnetTimeStamp {
104        let sequence = &mut self.sequence;
105        update_stamp(self.clock.as_deref(), || {
106            *sequence = next_sequence(*sequence);
107            *sequence
108        })
109    }
110}
111
112/// A client's simulated Reliability, written while Out_Of_Service is TRUE:
113/// an Enumerated inside the BACnetReliability production. Another datatype is
114/// INVALID_DATA_TYPE and another number VALUE_OUT_OF_RANGE.
115fn simulated_reliability(value: &PropertyValue) -> Result<Reliability, Error> {
116    let PropertyValue::Enumerated(raw) = value else {
117        return Err(common::invalid_data_type_error());
118    };
119    checked_reliability(Reliability::from_raw(*raw))
120}
121
122/// `reliability`, or VALUE_OUT_OF_RANGE outside the BACnetReliability
123/// production.
124fn checked_reliability(reliability: Reliability) -> Result<Reliability, Error> {
125    if common::is_reliability_value_valid(reliability) {
126        Ok(reliability)
127    } else {
128        Err(common::value_out_of_range_error())
129    }
130}
131
132/// The references a setter of one of the reference lists or arrays stores,
133/// each naming an object of `object_type` in this device or in the Device its
134/// device identifier names. A reference to another object type, or one whose
135/// device identifier isn't a Device (the shared `check_device_member`), is
136/// VALUE_OUT_OF_RANGE, so the setter keeps what it held.
137fn references_to(
138    object_type: ObjectType,
139    references: impl IntoIterator<Item = impl Into<BACnetDeviceObjectReference>>,
140) -> Result<Vec<BACnetDeviceObjectReference>, Error> {
141    let references: Vec<BACnetDeviceObjectReference> =
142        references.into_iter().map(Into::into).collect();
143    for reference in &references {
144        crate::device_reference::check_device_member(reference.device_identifier)?;
145        if reference.object_identifier.object_type() != object_type {
146            return Err(common::value_out_of_range_error());
147        }
148    }
149    Ok(references)
150}
151
152// ---------------------------------------------------------------------------
153
154mod credential;
155mod credential_data_input;
156mod credential_data_input_formats;
157mod credential_data_input_out_of_service;
158mod credential_rules;
159mod door;
160mod door_alarm;
161mod door_out_of_service;
162mod input;
163mod metadata_identity;
164mod metadata_topology;
165mod point;
166mod point_authorization;
167mod point_event_time;
168mod rights;
169mod rights_evaluation;
170mod rights_writes;
171mod user;
172mod zone;
173mod zone_occupancy;
174mod zone_out_of_service;
175pub use credential::*;
176pub use credential_data_input::*;
177pub use door::*;
178pub use input::*;
179pub use point::*;
180pub use rights::*;
181pub use rights_evaluation::*;
182pub use user::*;
183pub use zone::*;
184
185#[cfg(test)]
186mod array_tests;
187#[cfg(test)]
188mod constructed_value_tests;
189#[cfg(test)]
190mod credential_data_input_format_tests;
191#[cfg(test)]
192mod credential_data_input_out_of_service_tests;
193#[cfg(test)]
194mod credential_exemption_tests;
195#[cfg(test)]
196mod credential_tests;
197#[cfg(test)]
198mod device_reference_tests;
199#[cfg(test)]
200mod door_alarm_tests;
201#[cfg(test)]
202mod door_out_of_service_tests;
203#[cfg(test)]
204mod door_pulse_tests;
205#[cfg(test)]
206mod input_tests;
207#[cfg(test)]
208mod point_authorization_tests;
209#[cfg(test)]
210mod point_out_of_service_tests;
211#[cfg(test)]
212mod point_policy_tests;
213#[cfg(test)]
214mod point_status_tests;
215#[cfg(test)]
216mod tests;
217#[cfg(test)]
218mod typed_value_tests;
219#[cfg(test)]
220mod user_references_tests;
221#[cfg(test)]
222mod zone_event_tests;
223#[cfg(test)]
224mod zone_occupancy_tests;
225#[cfg(test)]
226mod zone_out_of_service_tests;
227#[cfg(test)]
228mod zone_points_tests;