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