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