bacnet_objects/event_enrollment/
alert.rs1use crate::prelude::*;
2use alloc::borrow::Cow;
3
4use bacnet_types::bitstring::EventTransitionBits;
5use bacnet_types::enums::{EventState, NotifyType, ObjectType, PropertyIdentifier};
6use bacnet_types::error::Error;
7use bacnet_types::primitives::{ObjectIdentifier, PropertyValue};
8
9use crate::common;
10use crate::event::history::EventHistory;
11use crate::property_metadata::PropertyMetadata;
12use crate::traits::BACnetObject;
13
14use super::metadata;
15
16pub struct AlertEnrollmentObject {
25 oid: ObjectIdentifier,
26 name: String,
27 description: String,
28 pub(super) event_state: EventState,
30 pub present_value: ObjectIdentifier,
32 pub event_detection_enable: bool,
41 pub(super) acked_transitions: EventTransitionBits,
43 pub(super) event_history: EventHistory,
44 pub event_enable: EventTransitionBits,
46 pub notification_class: u32,
48 notify_type: NotifyType,
51}
52
53impl AlertEnrollmentObject {
54 pub fn new(
57 instance: u32,
58 name: impl Into<String>,
59 initial_source: ObjectIdentifier,
60 ) -> Result<Self, Error> {
61 let oid = ObjectIdentifier::new(ObjectType::ALERT_ENROLLMENT, instance)?;
62 Ok(Self {
63 oid,
64 name: name.into(),
65 description: String::new(),
66 event_state: EventState::NORMAL,
67 present_value: initial_source,
68 event_detection_enable: true,
69 acked_transitions: EventTransitionBits::all(),
70 event_history: EventHistory::default(),
71 event_enable: EventTransitionBits::all(),
72 notification_class: 0,
73 notify_type: NotifyType::ALARM,
74 })
75 }
76
77 pub fn record_alert_source(&mut self, source: ObjectIdentifier) {
83 self.present_value = source;
84 }
85
86 pub fn set_event_detection_enable(&mut self, enabled: bool) {
90 if !enabled || !self.event_detection_enable {
91 self.event_state = EventState::NORMAL;
92 self.acked_transitions = EventTransitionBits::all();
93 self.event_history.reset();
94 }
95 self.event_detection_enable = enabled;
96 }
97
98 fn read_alert_common_property(
103 &self,
104 property: PropertyIdentifier,
105 array_index: Option<u32>,
106 ) -> Option<Result<PropertyValue, Error>> {
107 match property {
108 PropertyIdentifier::OBJECT_IDENTIFIER => {
109 Some(Ok(PropertyValue::ObjectIdentifier(self.oid)))
110 }
111 PropertyIdentifier::OBJECT_NAME => {
112 Some(Ok(PropertyValue::CharacterString(self.name.clone())))
113 }
114 PropertyIdentifier::DESCRIPTION => {
115 Some(Ok(PropertyValue::CharacterString(self.description.clone())))
116 }
117 PropertyIdentifier::PROPERTY_LIST => {
118 let properties = self.property_list();
119 Some(common::read_property_list_property(
120 &properties,
121 array_index,
122 ))
123 }
124 _ => None,
125 }
126 }
127}
128
129impl BACnetObject for AlertEnrollmentObject {
130 fn object_identifier(&self) -> ObjectIdentifier {
131 self.oid
132 }
133
134 fn object_name(&self) -> &str {
135 &self.name
136 }
137
138 fn read_property(
139 &self,
140 property: PropertyIdentifier,
141 array_index: Option<u32>,
142 ) -> Result<PropertyValue, Error> {
143 if !self.event_detection_enable
146 && matches!(
147 property,
148 PropertyIdentifier::EVENT_TIME_STAMPS | PropertyIdentifier::EVENT_MESSAGE_TEXTS
149 )
150 {
151 return EventHistory::default()
152 .read(property, array_index)
153 .expect("EventHistory handles the history arrays");
154 }
155 if let Some(result) = self.event_history.read(property, array_index) {
159 return result;
160 }
161 if let Some(result) = self.read_alert_common_property(property, array_index) {
162 return result;
163 }
164 match property {
165 p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
166 ObjectType::ALERT_ENROLLMENT.to_raw(),
167 )),
168 p if p == PropertyIdentifier::PRESENT_VALUE => {
169 Ok(PropertyValue::ObjectIdentifier(self.present_value))
170 }
171 p if p == PropertyIdentifier::EVENT_DETECTION_ENABLE => {
172 Ok(PropertyValue::Boolean(self.event_detection_enable))
173 }
174 p if p == PropertyIdentifier::EVENT_ENABLE => Ok(PropertyValue::BitString {
175 unused_bits: 5,
176 data: vec![self.event_enable.to_bacnet()],
177 }),
178 p if p == PropertyIdentifier::NOTIFICATION_CLASS => {
179 Ok(PropertyValue::Unsigned(self.notification_class as u64))
180 }
181 p if p == PropertyIdentifier::NOTIFY_TYPE => {
182 Ok(PropertyValue::Enumerated(self.notify_type.to_raw()))
183 }
184 p if p == PropertyIdentifier::EVENT_STATE => Ok(PropertyValue::Enumerated(
185 if self.event_detection_enable {
186 self.event_state
187 } else {
188 EventState::NORMAL
189 }
190 .to_raw(),
191 )),
192 p if p == PropertyIdentifier::ACKED_TRANSITIONS => Ok(PropertyValue::BitString {
193 unused_bits: 5,
194 data: vec![
195 if self.event_detection_enable {
196 self.acked_transitions
197 } else {
198 EventTransitionBits::all()
199 }
200 .to_bacnet(),
201 ],
202 }),
203 _ => Err(common::unknown_property_error()),
204 }
205 }
206
207 fn write_property(
208 &mut self,
209 property: PropertyIdentifier,
210 array_index: Option<u32>,
211 value: PropertyValue,
212 _priority: Option<u8>,
213 ) -> Result<(), Error> {
214 if property == PropertyIdentifier::EVENT_DETECTION_ENABLE {
215 if let PropertyValue::Boolean(v) = value {
216 self.set_event_detection_enable(v);
217 return Ok(());
218 }
219 return Err(common::invalid_data_type_error());
220 }
221 if property == PropertyIdentifier::EVENT_ENABLE {
222 if let PropertyValue::BitString { unused_bits, data } = &value {
225 let byte = common::check_fixed_width_bit_string(*unused_bits, data, 3)?;
226 self.event_enable = EventTransitionBits::from_bacnet(&[byte]);
227 return Ok(());
228 }
229 return Err(common::invalid_data_type_error());
230 }
231 if property == PropertyIdentifier::NOTIFICATION_CLASS {
232 if let PropertyValue::Unsigned(v) = value {
233 self.notification_class = common::u64_to_u32(v)?;
234 return Ok(());
235 }
236 return Err(common::invalid_data_type_error());
237 }
238 if property == PropertyIdentifier::NOTIFY_TYPE {
239 if let PropertyValue::Enumerated(v) = value {
240 let notify_type = NotifyType::from_raw(v);
241 if notify_type != NotifyType::ALARM && notify_type != NotifyType::EVENT {
242 return Err(common::value_out_of_range_error());
243 }
244 self.notify_type = notify_type;
245 return Ok(());
246 }
247 return Err(common::invalid_data_type_error());
248 }
249 if let Some(result) =
250 self.event_history
251 .write(property, array_index, &value, self.event_detection_enable)
252 {
253 return result;
254 }
255 if let Some(result) = common::write_description(&mut self.description, property, &value) {
256 return result;
257 }
258 Err(crate::common::unhandled_write_error(
259 self.property_metadata().as_ref(),
260 property,
261 array_index,
262 ))
263 }
264
265 fn set_event_state_internal(&mut self, state: EventState) -> Result<(), Error> {
266 if !self.event_detection_enable && state != EventState::NORMAL {
267 return Err(common::write_access_denied_error());
268 }
269 self.event_state = state;
270 Ok(())
271 }
272
273 fn set_acked_transitions_internal(
274 &mut self,
275 transition_bit: EventTransitionBits,
276 acknowledged: bool,
277 ) -> Result<(), Error> {
278 if !self.event_detection_enable {
279 return Err(common::write_access_denied_error());
280 }
281 let transition_bit = transition_bit & EventTransitionBits::all();
282 if acknowledged {
283 self.acked_transitions.insert(transition_bit);
284 } else {
285 self.acked_transitions
289 .remove(transition_bit.difference(EventTransitionBits::TO_NORMAL));
290 }
291 self.acked_transitions
292 .insert(EventTransitionBits::TO_NORMAL);
293 Ok(())
294 }
295
296 fn is_writable_property(&self, property: PropertyIdentifier) -> bool {
297 matches!(
298 property,
299 PropertyIdentifier::DESCRIPTION
300 | PropertyIdentifier::EVENT_DETECTION_ENABLE
301 | PropertyIdentifier::EVENT_ENABLE
302 | PropertyIdentifier::NOTIFICATION_CLASS
303 | PropertyIdentifier::NOTIFY_TYPE
304 | PropertyIdentifier::EVENT_MESSAGE_TEXTS_CONFIG
305 | PropertyIdentifier::EVENT_ALGORITHM_INHIBIT_REF
306 | PropertyIdentifier::EVENT_ALGORITHM_INHIBIT
307 )
308 }
309
310 fn event_algorithm_inhibit_reference_internal(
311 &self,
312 ) -> Option<bacnet_types::constructed::BACnetObjectPropertyReference> {
313 self.event_history.options.inhibit_reference().cloned()
314 }
315
316 fn follow_event_algorithm_inhibit_internal(&mut self, inhibit: bool) -> bool {
317 self.event_history.options.follow(inhibit)
318 }
319
320 fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
321 Cow::Borrowed(metadata::ALERT_ENROLLMENT_PROPERTIES)
322 }
323
324 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
325 crate::property_metadata::property_list_from_metadata(metadata::ALERT_ENROLLMENT_PROPERTIES)
326 }
327}