1use crate::prelude::*;
4use alloc::borrow::Cow;
5use alloc::collections::VecDeque;
6use alloc::sync::Arc;
7
8use bacnet_types::bitstring::EventTransitionBits;
9use bacnet_types::constructed::BACnetEventLogRecord;
10use bacnet_types::enums::{NotifyType, ObjectType, PropertyIdentifier, Reliability};
11use bacnet_types::error::Error;
12use bacnet_types::primitives::{Date, ObjectIdentifier, PropertyValue, StatusFlags, Time};
13
14use crate::clock::ClockReader;
15use crate::common::{self, read_common_properties};
16use crate::log_buffer::{
17 LogBufferRecords, LogRecordBuffer, LogRecordIdentity, log_buffer_read_denied,
18};
19use crate::log_lifecycle::LogLifecycle;
20use crate::log_persistence::store::{DurableLog, LogStore};
21use crate::log_reporting::{BufferReadyReporting, impl_buffer_ready_reporting};
22use crate::log_window::LogWindow;
23use crate::traits::BACnetObject;
24
25mod durable;
26mod metadata;
27
28pub struct EventLogObject {
48 oid: ObjectIdentifier,
49 name: String,
50 description: String,
51 log_enable: bool,
52 stop_when_full: bool,
53 buffer_size: u32,
54 log_buffer: LogRecordBuffer<BACnetEventLogRecord>,
55 status_flags: StatusFlags,
56 reliability: Reliability,
57 window: LogWindow,
58 reporting: BufferReadyReporting,
59 log_received_notifications: bool,
60 clock: Option<Arc<dyn ClockReader>>,
61 store: Option<LogStore<BACnetEventLogRecord>>,
63}
64
65impl EventLogObject {
66 pub fn new(instance: u32, name: impl Into<String>, buffer_size: u32) -> Result<Self, Error> {
68 let oid = ObjectIdentifier::new(ObjectType::EVENT_LOG, instance)?;
69 Ok(Self {
70 oid,
71 name: name.into(),
72 description: String::new(),
73 log_enable: true,
74 stop_when_full: false,
75 buffer_size,
76 log_buffer: LogRecordBuffer::new(buffer_size),
77 status_flags: StatusFlags::empty(),
78 reliability: Reliability::NO_FAULT_DETECTED,
79 window: LogWindow::default(),
80 reporting: BufferReadyReporting::default(),
81 log_received_notifications: false,
82 clock: None,
83 store: None,
84 })
85 }
86
87 pub fn add_record(&mut self, record: BACnetEventLogRecord) -> Result<(), Error> {
99 self.settle_interruption(Some((record.date, record.time)));
100 self.lifecycle().try_add_ordinary(record)?;
101 self.commit_if_counted();
102 Ok(())
103 }
104
105 pub fn records(&self) -> &VecDeque<BACnetEventLogRecord> {
107 self.log_buffer.records()
108 }
109
110 pub fn total_record_count(&self) -> u32 {
114 self.log_buffer.total_record_count()
115 }
116
117 pub fn restore_log_buffer(
124 &mut self,
125 total_record_count: u32,
126 records: impl IntoIterator<Item = BACnetEventLogRecord>,
127 ) -> Result<(), Error> {
128 self.lifecycle()
129 .restore(total_record_count, records.into_iter().collect())
130 }
131
132 pub fn record_interruption(&mut self, date: Date, time: Time) -> Result<(), Error> {
138 self.lifecycle().record_interruption((date, time))?;
139 if let Some(store) = &mut self.store {
140 store.interruption_recorded();
141 }
142 self.commit_if_counted();
143 Ok(())
144 }
145
146 pub fn clear(&mut self) {
148 self.log_buffer.clear();
149 }
150
151 pub fn set_description(&mut self, desc: impl Into<String>) {
153 self.description = desc.into();
154 }
155
156 pub fn set_start_time(&mut self, date: Date, time: Time) -> Result<(), Error> {
165 self.lifecycle()
166 .configure_window(PropertyIdentifier::START_TIME, (date, time))
167 }
168
169 pub fn set_stop_time(&mut self, date: Date, time: Time) -> Result<(), Error> {
173 self.lifecycle()
174 .configure_window(PropertyIdentifier::STOP_TIME, (date, time))
175 }
176
177 pub fn logs_received_notifications(&self) -> bool {
180 self.log_received_notifications
181 }
182
183 pub fn set_log_received_notifications(&mut self, log: bool) {
190 self.log_received_notifications = log;
191 }
192
193 pub fn set_notification_threshold(&mut self, threshold: u32) {
196 self.reporting.set_notification_threshold(threshold);
197 }
198
199 pub fn set_notification_class(&mut self, class: u32) {
202 self.reporting.set_notification_class(class);
203 }
204
205 pub fn set_event_enable(&mut self, enable: EventTransitionBits) {
208 self.reporting.set_event_enable(enable);
209 }
210
211 pub fn set_notify_type(&mut self, notify_type: NotifyType) {
213 self.reporting.set_notify_type(notify_type);
214 }
215
216 fn lifecycle(&mut self) -> LogLifecycle<'_, BACnetEventLogRecord> {
217 LogLifecycle::new(
218 &mut self.log_buffer,
219 &mut self.log_enable,
220 &mut self.stop_when_full,
221 self.clock.as_ref(),
222 &mut self.window,
223 &mut self.reporting,
224 )
225 }
226}
227
228impl BACnetObject for EventLogObject {
229 fn object_identifier(&self) -> ObjectIdentifier {
230 self.oid
231 }
232
233 fn object_name(&self) -> &str {
234 &self.name
235 }
236
237 fn read_property(
238 &self,
239 property: PropertyIdentifier,
240 array_index: Option<u32>,
241 ) -> Result<PropertyValue, Error> {
242 if let Some(result) =
245 read_common_properties!(self, property, array_index, no_out_of_service)
246 {
247 return result;
248 }
249 if let Some(value) = self.window.read(property) {
250 return Ok(value);
251 }
252 let total = self.log_buffer.total_record_count();
253 if let Some(result) = self.reporting.read(property, array_index, total) {
254 return result;
255 }
256 match property {
257 p if p == PropertyIdentifier::OBJECT_TYPE => {
258 Ok(PropertyValue::Enumerated(ObjectType::EVENT_LOG.to_raw()))
259 }
260 p if p == PropertyIdentifier::LOG_ENABLE => Ok(PropertyValue::Boolean(self.log_enable)),
261 p if p == PropertyIdentifier::STOP_WHEN_FULL => {
262 Ok(PropertyValue::Boolean(self.stop_when_full))
263 }
264 p if p == PropertyIdentifier::BUFFER_SIZE => {
265 Ok(PropertyValue::Unsigned(self.buffer_size as u64))
266 }
267 p if p == PropertyIdentifier::LOG_BUFFER => Err(log_buffer_read_denied()),
269 p if p == PropertyIdentifier::RECORD_COUNT => {
270 Ok(PropertyValue::Unsigned(self.records().len() as u64))
271 }
272 p if p == PropertyIdentifier::TOTAL_RECORD_COUNT => {
273 Ok(PropertyValue::Unsigned(u64::from(total)))
274 }
275 _ => Err(common::unknown_property_error()),
276 }
277 }
278
279 fn write_property(
280 &mut self,
281 property: PropertyIdentifier,
282 array_index: Option<u32>,
283 value: PropertyValue,
284 _priority: Option<u8>,
285 ) -> Result<(), Error> {
286 if property == PropertyIdentifier::LOG_ENABLE {
287 if let PropertyValue::Boolean(v) = value {
288 return self.lifecycle().write_enable(v);
289 }
290 return Err(common::invalid_data_type_error());
291 }
292 if let Some(result) = self.window.write(property, &value) {
293 result?;
295 self.lifecycle().refresh_window();
296 return Ok(());
297 }
298 if property == PropertyIdentifier::STOP_WHEN_FULL {
299 if let PropertyValue::Boolean(v) = value {
300 return self.lifecycle().write_stop_when_full(v);
301 }
302 return Err(common::invalid_data_type_error());
303 }
304 if property == PropertyIdentifier::RECORD_COUNT {
305 if let PropertyValue::Unsigned(0) = value {
306 return self.lifecycle().purge();
307 }
308 return Err(common::invalid_data_type_error());
309 }
310 let total = self.log_buffer.total_record_count();
311 if let Some(result) = self.reporting.write(property, array_index, &value, total) {
312 return result;
313 }
314 if let Some(result) = common::write_description(&mut self.description, property, &value) {
315 return result;
316 }
317 Err(crate::common::unhandled_write_error(
318 self.property_metadata().as_ref(),
319 property,
320 array_index,
321 ))
322 }
323
324 fn property_metadata(&self) -> Cow<'_, [crate::property_metadata::PropertyMetadata]> {
325 metadata::for_object(self)
326 }
327
328 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
329 crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
330 }
331
332 fn bind_clock_internal(&mut self, clock: Option<Arc<dyn ClockReader>>) {
333 self.clock = clock;
334 self.settle_interruption(None);
335 }
336
337 fn durable_writes_internal(&mut self) -> Option<&mut dyn crate::durable::DurableWrites> {
338 self.store.is_some().then_some(self as _)
339 }
340
341 fn advance_monotonic_time_internal(&mut self, now: core::time::Duration) -> bool {
342 self.commit_if_interval(now);
343 false
344 }
345
346 fn log_record_identities_internal(&self) -> Option<Vec<LogRecordIdentity>> {
347 Some(self.log_buffer.identities())
348 }
349
350 fn log_buffer_internal(&self) -> Option<&dyn LogBufferRecords> {
351 Some(&self.log_buffer)
352 }
353
354 fn add_event_log_record(&mut self, record: BACnetEventLogRecord) -> Result<(), Error> {
355 self.add_record(record)
356 }
357
358 fn refresh_log_window_internal(&mut self) -> bool {
359 self.settle_interruption(None);
360 let recorded = self.lifecycle().refresh_window();
361 self.commit_if_counted();
362 recorded
363 }
364
365 fn logs_received_event_notifications_internal(&self) -> bool {
366 self.log_received_notifications
367 }
368
369 impl_buffer_ready_reporting!(reporting, log_buffer);
370}
371
372#[cfg(test)]
373mod tests;