Skip to main content

bacnet_objects/access_control/
point.rs

1use super::*;
2
3// AccessPointObject (type 33)
4// ---------------------------------------------------------------------------
5
6/// BACnet Access Point object (type 33).
7///
8/// Represents an access point (reader/controller at a door) in an access control system.
9/// Present value indicates the most recent access event.
10pub struct AccessPointObject {
11    oid: ObjectIdentifier,
12    name: String,
13    description: String,
14    present_value: u32, // AccessEvent enumeration
15    access_event: u32,
16    access_event_tag: u64,
17    access_event_time: ([u8; 4], [u8; 4]), // (Date, Time) as raw bytes
18    access_doors: Vec<ObjectIdentifier>,
19    event_state: u32,
20    status_flags: StatusFlags,
21    out_of_service: bool,
22    reliability: u32,
23}
24
25impl AccessPointObject {
26    /// Create a new Access Point object.
27    pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
28        let oid = ObjectIdentifier::new(ObjectType::ACCESS_POINT, instance)?;
29        Ok(Self {
30            oid,
31            name: name.into(),
32            description: String::new(),
33            present_value: 0,
34            access_event: 0,
35            access_event_tag: 0,
36            access_event_time: ([0xFF, 0xFF, 0xFF, 0xFF], [0xFF, 0xFF, 0xFF, 0xFF]),
37            access_doors: Vec::new(),
38            event_state: 0,
39            status_flags: StatusFlags::empty(),
40            out_of_service: false,
41            reliability: 0,
42        })
43    }
44}
45
46impl BACnetObject for AccessPointObject {
47    fn object_identifier(&self) -> ObjectIdentifier {
48        self.oid
49    }
50
51    fn object_name(&self) -> &str {
52        &self.name
53    }
54
55    fn read_property(
56        &self,
57        property: PropertyIdentifier,
58        array_index: Option<u32>,
59    ) -> Result<PropertyValue, Error> {
60        if let Some(result) = read_common_properties!(self, property, array_index) {
61            return result;
62        }
63        match property {
64            p if p == PropertyIdentifier::OBJECT_TYPE => {
65                Ok(PropertyValue::Enumerated(ObjectType::ACCESS_POINT.to_raw()))
66            }
67            p if p == PropertyIdentifier::PRESENT_VALUE => {
68                Ok(PropertyValue::Enumerated(self.present_value))
69            }
70            p if p == PropertyIdentifier::ACCESS_EVENT => {
71                Ok(PropertyValue::Enumerated(self.access_event))
72            }
73            p if p == PropertyIdentifier::ACCESS_EVENT_TAG => {
74                Ok(PropertyValue::Unsigned(self.access_event_tag))
75            }
76            p if p == PropertyIdentifier::ACCESS_EVENT_TIME => {
77                let (d, t) = &self.access_event_time;
78                Ok(PropertyValue::List(vec![
79                    PropertyValue::Date(Date {
80                        year: d[0],
81                        month: d[1],
82                        day: d[2],
83                        day_of_week: d[3],
84                    }),
85                    PropertyValue::Time(Time {
86                        hour: t[0],
87                        minute: t[1],
88                        second: t[2],
89                        hundredths: t[3],
90                    }),
91                ]))
92            }
93            p if p == PropertyIdentifier::ACCESS_DOORS => Ok(PropertyValue::List(
94                self.access_doors
95                    .iter()
96                    .map(|oid| PropertyValue::ObjectIdentifier(*oid))
97                    .collect(),
98            )),
99            p if p == PropertyIdentifier::EVENT_STATE => {
100                Ok(PropertyValue::Enumerated(self.event_state))
101            }
102            _ => Err(common::unknown_property_error()),
103        }
104    }
105
106    fn write_property(
107        &mut self,
108        property: PropertyIdentifier,
109        _array_index: Option<u32>,
110        value: PropertyValue,
111        _priority: Option<u8>,
112    ) -> Result<(), Error> {
113        if let Some(result) =
114            common::write_out_of_service(&mut self.out_of_service, property, &value)
115        {
116            return result;
117        }
118        if let Some(result) = common::write_description(&mut self.description, property, &value) {
119            return result;
120        }
121        match property {
122            p if p == PropertyIdentifier::PRESENT_VALUE => {
123                if let PropertyValue::Enumerated(v) = value {
124                    self.present_value = v;
125                    Ok(())
126                } else {
127                    Err(common::invalid_data_type_error())
128                }
129            }
130            _ => Err(common::write_access_denied_error()),
131        }
132    }
133
134    fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
135        static PROPS: &[PropertyIdentifier] = &[
136            PropertyIdentifier::OBJECT_IDENTIFIER,
137            PropertyIdentifier::OBJECT_NAME,
138            PropertyIdentifier::DESCRIPTION,
139            PropertyIdentifier::OBJECT_TYPE,
140            PropertyIdentifier::PRESENT_VALUE,
141            PropertyIdentifier::ACCESS_EVENT,
142            PropertyIdentifier::ACCESS_EVENT_TAG,
143            PropertyIdentifier::ACCESS_EVENT_TIME,
144            PropertyIdentifier::ACCESS_DOORS,
145            PropertyIdentifier::EVENT_STATE,
146            PropertyIdentifier::STATUS_FLAGS,
147            PropertyIdentifier::OUT_OF_SERVICE,
148            PropertyIdentifier::RELIABILITY,
149        ];
150        Cow::Borrowed(PROPS)
151    }
152}
153
154// ---------------------------------------------------------------------------