bacnet_objects/access_control/
door.rs1use super::*;
2
3pub struct AccessDoorObject {
12 oid: ObjectIdentifier,
13 name: String,
14 description: String,
15 present_value: u32, door_status: u32, lock_status: u32, secured_status: u32, door_alarm_state: u32, door_members: Vec<ObjectIdentifier>,
21 status_flags: StatusFlags,
22 event_state: u32,
24 out_of_service: bool,
25 reliability: u32,
26 priority_array: [Option<u32>; 16],
28 relinquish_default: u32,
29}
30
31struct AccessDoorWriteRollback {
32 priority_array: [Option<u32>; 16],
33}
34
35impl AccessDoorObject {
36 pub fn new(instance: u32, name: impl Into<String>) -> Result<Self, Error> {
38 let oid = ObjectIdentifier::new(ObjectType::ACCESS_DOOR, instance)?;
39 Ok(Self {
40 oid,
41 name: name.into(),
42 description: String::new(),
43 present_value: 0, door_status: 0, lock_status: 0,
46 secured_status: 0,
47 door_alarm_state: 0,
48 door_members: Vec::new(),
49 status_flags: StatusFlags::empty(),
50 event_state: 0, out_of_service: false,
52 reliability: 0,
53 priority_array: Default::default(),
54 relinquish_default: 0, })
56 }
57
58 pub fn set_relinquish_default(&mut self, value: u32) -> Result<(), Error> {
70 if value > DoorValue::EXTENDED_PULSE_UNLOCK.to_raw() {
71 return Err(common::value_out_of_range_error());
72 }
73 self.relinquish_default = value;
74 self.recalculate_present_value();
75 Ok(())
76 }
77
78 fn recalculate_present_value(&mut self) {
79 self.present_value = self
80 .priority_array
81 .iter()
82 .flatten()
83 .next()
84 .copied()
85 .unwrap_or(self.relinquish_default);
86 }
87}
88
89impl BACnetObject for AccessDoorObject {
90 fn object_identifier(&self) -> ObjectIdentifier {
91 self.oid
92 }
93
94 fn object_name(&self) -> &str {
95 &self.name
96 }
97
98 fn read_property(
99 &self,
100 property: PropertyIdentifier,
101 array_index: Option<u32>,
102 ) -> Result<PropertyValue, Error> {
103 if let Some(result) = read_common_properties!(self, property, array_index) {
104 return result;
105 }
106 match property {
107 p if p == PropertyIdentifier::OBJECT_TYPE => {
108 Ok(PropertyValue::Enumerated(ObjectType::ACCESS_DOOR.to_raw()))
109 }
110 p if p == PropertyIdentifier::PRESENT_VALUE => {
111 Ok(PropertyValue::Enumerated(self.present_value))
112 }
113 p if p == PropertyIdentifier::DOOR_STATUS => {
114 Ok(PropertyValue::Enumerated(self.door_status))
115 }
116 p if p == PropertyIdentifier::LOCK_STATUS => {
117 Ok(PropertyValue::Enumerated(self.lock_status))
118 }
119 p if p == PropertyIdentifier::SECURED_STATUS => {
120 Ok(PropertyValue::Enumerated(self.secured_status))
121 }
122 p if p == PropertyIdentifier::DOOR_ALARM_STATE => {
123 Ok(PropertyValue::Enumerated(self.door_alarm_state))
124 }
125 p if p == PropertyIdentifier::DOOR_MEMBERS => Ok(PropertyValue::List(
126 self.door_members
127 .iter()
128 .map(|oid| PropertyValue::ObjectIdentifier(*oid))
129 .collect(),
130 )),
131 p if p == PropertyIdentifier::EVENT_STATE => {
132 Ok(PropertyValue::Enumerated(self.event_state))
133 }
134 p if p == PropertyIdentifier::PRIORITY_ARRAY => {
135 common::read_priority_array!(self, array_index, PropertyValue::Enumerated)
136 }
137 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
138 Ok(PropertyValue::Enumerated(self.relinquish_default))
139 }
140 _ => Err(common::unknown_property_error()),
141 }
142 }
143
144 fn write_property(
145 &mut self,
146 property: PropertyIdentifier,
147 _array_index: Option<u32>,
148 value: PropertyValue,
149 priority: Option<u8>,
150 ) -> Result<(), Error> {
151 if let Some(result) =
152 common::write_out_of_service(&mut self.out_of_service, property, &value)
153 {
154 return result;
155 }
156 if let Some(result) = common::write_description(&mut self.description, property, &value) {
157 return result;
158 }
159 match property {
160 p if p == PropertyIdentifier::PRESENT_VALUE => {
161 let slot = priority.unwrap_or(16).clamp(1, 16) as usize - 1;
162 if let PropertyValue::Null = value {
163 self.priority_array[slot] = None;
165 } else if let PropertyValue::Enumerated(v) = value {
166 self.priority_array[slot] = Some(v);
167 } else if self.out_of_service {
168 if let PropertyValue::Enumerated(v) = value {
170 self.present_value = v;
171 return Ok(());
172 }
173 return Err(common::invalid_data_type_error());
174 } else {
175 return Err(common::invalid_data_type_error());
176 }
177 self.recalculate_present_value();
179 Ok(())
180 }
181 p if p == PropertyIdentifier::RELINQUISH_DEFAULT => {
184 if let PropertyValue::Enumerated(v) = value {
185 return self.set_relinquish_default(v);
186 }
187 Err(common::invalid_data_type_error())
188 }
189 _ => Err(common::write_access_denied_error()),
190 }
191 }
192
193 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
194 static PROPS: &[PropertyIdentifier] = &[
195 PropertyIdentifier::OBJECT_IDENTIFIER,
196 PropertyIdentifier::OBJECT_NAME,
197 PropertyIdentifier::DESCRIPTION,
198 PropertyIdentifier::OBJECT_TYPE,
199 PropertyIdentifier::PRESENT_VALUE,
200 PropertyIdentifier::DOOR_STATUS,
201 PropertyIdentifier::LOCK_STATUS,
202 PropertyIdentifier::SECURED_STATUS,
203 PropertyIdentifier::DOOR_ALARM_STATE,
204 PropertyIdentifier::DOOR_MEMBERS,
205 PropertyIdentifier::STATUS_FLAGS,
206 PropertyIdentifier::OUT_OF_SERVICE,
207 PropertyIdentifier::RELIABILITY,
208 ];
209 Cow::Borrowed(PROPS)
210 }
211
212 fn capture_write_property_rollback(
213 &mut self,
214 property: PropertyIdentifier,
215 _value: &PropertyValue,
216 ) -> Option<crate::traits::WritePropertyRollback> {
217 (property == PropertyIdentifier::PRESENT_VALUE).then(|| {
218 crate::traits::WritePropertyRollback::new(AccessDoorWriteRollback {
219 priority_array: self.priority_array,
220 })
221 })
222 }
223
224 fn restore_write_property_rollback(
225 &mut self,
226 rollback: crate::traits::WritePropertyRollback,
227 ) -> Result<(), Error> {
228 self.priority_array = rollback
229 .downcast::<AccessDoorWriteRollback>()?
230 .priority_array;
231 self.recalculate_present_value();
232 Ok(())
233 }
234
235 fn supports_cov(&self) -> bool {
236 true
237 }
238
239 fn is_writable_property(&self, property: PropertyIdentifier) -> bool {
240 matches!(
243 property,
244 PropertyIdentifier::OUT_OF_SERVICE
245 | PropertyIdentifier::DESCRIPTION
246 | PropertyIdentifier::PRESENT_VALUE
247 | PropertyIdentifier::RELINQUISH_DEFAULT
248 )
249 }
250}
251
252