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_reporting::{impl_buffer_ready_reporting, BufferReadyReporting};
20use crate::log_window::LogWindow;
21use crate::traits::BACnetObject;
22
23mod metadata;
24
25pub struct EventLogObject {
45 oid: ObjectIdentifier,
46 name: String,
47 description: String,
48 log_enable: bool,
49 stop_when_full: bool,
50 buffer_size: u32,
51 log_buffer: LogRecordBuffer<BACnetEventLogRecord>,
52 status_flags: StatusFlags,
53 reliability: Reliability,
54 window: LogWindow,
55 reporting: BufferReadyReporting,
56 log_received_notifications: bool,
57 clock: Option<Arc<dyn ClockReader>>,
58}
59
60impl EventLogObject {
61 pub fn new(instance: u32, name: impl Into<String>, buffer_size: u32) -> Result<Self, Error> {
63 let oid = ObjectIdentifier::new(ObjectType::EVENT_LOG, instance)?;
64 Ok(Self {
65 oid,
66 name: name.into(),
67 description: String::new(),
68 log_enable: true,
69 stop_when_full: false,
70 buffer_size,
71 log_buffer: LogRecordBuffer::new(buffer_size),
72 status_flags: StatusFlags::empty(),
73 reliability: Reliability::NO_FAULT_DETECTED,
74 window: LogWindow::default(),
75 reporting: BufferReadyReporting::default(),
76 log_received_notifications: false,
77 clock: None,
78 })
79 }
80
81 pub fn add_record(&mut self, record: BACnetEventLogRecord) -> Result<(), Error> {
93 self.lifecycle().try_add_ordinary(record).map(|_| ())
94 }
95
96 pub fn records(&self) -> &VecDeque<BACnetEventLogRecord> {
98 self.log_buffer.records()
99 }
100
101 pub fn total_record_count(&self) -> u32 {
105 self.log_buffer.total_record_count()
106 }
107
108 pub fn restore_log_buffer(
115 &mut self,
116 total_record_count: u32,
117 records: impl IntoIterator<Item = BACnetEventLogRecord>,
118 ) -> Result<(), Error> {
119 self.lifecycle()
120 .restore(total_record_count, records.into_iter().collect())
121 }
122
123 pub fn record_interruption(&mut self, date: Date, time: Time) -> Result<(), Error> {
127 self.lifecycle().record_interruption((date, time))
128 }
129
130 pub fn clear(&mut self) {
132 self.log_buffer.clear();
133 }
134
135 pub fn set_description(&mut self, desc: impl Into<String>) {
137 self.description = desc.into();
138 }
139
140 pub fn set_start_time(&mut self, date: Date, time: Time) -> Result<(), Error> {
149 self.lifecycle()
150 .configure_window(PropertyIdentifier::START_TIME, (date, time))
151 }
152
153 pub fn set_stop_time(&mut self, date: Date, time: Time) -> Result<(), Error> {
157 self.lifecycle()
158 .configure_window(PropertyIdentifier::STOP_TIME, (date, time))
159 }
160
161 pub fn logs_received_notifications(&self) -> bool {
164 self.log_received_notifications
165 }
166
167 pub fn set_log_received_notifications(&mut self, log: bool) {
174 self.log_received_notifications = log;
175 }
176
177 pub fn set_notification_threshold(&mut self, threshold: u32) {
180 self.reporting.set_notification_threshold(threshold);
181 }
182
183 pub fn set_notification_class(&mut self, class: u32) {
186 self.reporting.set_notification_class(class);
187 }
188
189 pub fn set_event_enable(&mut self, enable: EventTransitionBits) {
192 self.reporting.set_event_enable(enable);
193 }
194
195 pub fn set_notify_type(&mut self, notify_type: NotifyType) {
197 self.reporting.set_notify_type(notify_type);
198 }
199
200 fn lifecycle(&mut self) -> LogLifecycle<'_, BACnetEventLogRecord> {
201 LogLifecycle::new(
202 &mut self.log_buffer,
203 &mut self.log_enable,
204 &mut self.stop_when_full,
205 self.clock.as_ref(),
206 &mut self.window,
207 &mut self.reporting,
208 )
209 }
210}
211
212impl BACnetObject for EventLogObject {
213 fn object_identifier(&self) -> ObjectIdentifier {
214 self.oid
215 }
216
217 fn object_name(&self) -> &str {
218 &self.name
219 }
220
221 fn read_property(
222 &self,
223 property: PropertyIdentifier,
224 array_index: Option<u32>,
225 ) -> Result<PropertyValue, Error> {
226 if let Some(result) =
229 read_common_properties!(self, property, array_index, no_out_of_service)
230 {
231 return result;
232 }
233 if let Some(value) = self.window.read(property) {
234 return Ok(value);
235 }
236 let total = self.log_buffer.total_record_count();
237 if let Some(result) = self.reporting.read(property, array_index, total) {
238 return result;
239 }
240 match property {
241 p if p == PropertyIdentifier::OBJECT_TYPE => {
242 Ok(PropertyValue::Enumerated(ObjectType::EVENT_LOG.to_raw()))
243 }
244 p if p == PropertyIdentifier::LOG_ENABLE => Ok(PropertyValue::Boolean(self.log_enable)),
245 p if p == PropertyIdentifier::STOP_WHEN_FULL => {
246 Ok(PropertyValue::Boolean(self.stop_when_full))
247 }
248 p if p == PropertyIdentifier::BUFFER_SIZE => {
249 Ok(PropertyValue::Unsigned(self.buffer_size as u64))
250 }
251 p if p == PropertyIdentifier::LOG_BUFFER => Err(log_buffer_read_denied()),
253 p if p == PropertyIdentifier::RECORD_COUNT => {
254 Ok(PropertyValue::Unsigned(self.records().len() as u64))
255 }
256 p if p == PropertyIdentifier::TOTAL_RECORD_COUNT => {
257 Ok(PropertyValue::Unsigned(u64::from(total)))
258 }
259 _ => Err(common::unknown_property_error()),
260 }
261 }
262
263 fn write_property(
264 &mut self,
265 property: PropertyIdentifier,
266 array_index: Option<u32>,
267 value: PropertyValue,
268 _priority: Option<u8>,
269 ) -> Result<(), Error> {
270 if property == PropertyIdentifier::LOG_ENABLE {
271 if let PropertyValue::Boolean(v) = value {
272 return self.lifecycle().write_enable(v);
273 }
274 return Err(common::invalid_data_type_error());
275 }
276 if let Some(result) = self.window.write(property, &value) {
277 result?;
279 self.lifecycle().refresh_window();
280 return Ok(());
281 }
282 if property == PropertyIdentifier::STOP_WHEN_FULL {
283 if let PropertyValue::Boolean(v) = value {
284 return self.lifecycle().write_stop_when_full(v);
285 }
286 return Err(common::invalid_data_type_error());
287 }
288 if property == PropertyIdentifier::RECORD_COUNT {
289 if let PropertyValue::Unsigned(0) = value {
290 return self.lifecycle().purge();
291 }
292 return Err(common::invalid_data_type_error());
293 }
294 let total = self.log_buffer.total_record_count();
295 if let Some(result) = self.reporting.write(property, array_index, &value, total) {
296 return result;
297 }
298 if let Some(result) = common::write_description(&mut self.description, property, &value) {
299 return result;
300 }
301 Err(crate::common::unhandled_write_error(
302 self.property_metadata().as_ref(),
303 property,
304 array_index,
305 ))
306 }
307
308 fn property_metadata(&self) -> Cow<'_, [crate::property_metadata::PropertyMetadata]> {
309 metadata::for_object(self)
310 }
311
312 fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
313 crate::property_metadata::property_list_from_metadata(self.property_metadata().as_ref())
314 }
315
316 fn bind_clock_internal(&mut self, clock: Option<Arc<dyn ClockReader>>) {
317 self.clock = clock;
318 }
319
320 fn log_record_identities_internal(&self) -> Option<Vec<LogRecordIdentity>> {
321 Some(self.log_buffer.identities())
322 }
323
324 fn log_buffer_internal(&self) -> Option<&dyn LogBufferRecords> {
325 Some(&self.log_buffer)
326 }
327
328 fn add_event_log_record(&mut self, record: BACnetEventLogRecord) -> Result<(), Error> {
329 self.add_record(record)
330 }
331
332 fn refresh_log_window_internal(&mut self) -> bool {
333 self.lifecycle().refresh_window()
334 }
335
336 fn logs_received_event_notifications_internal(&self) -> bool {
337 self.log_received_notifications
338 }
339
340 impl_buffer_ready_reporting!(reporting, log_buffer);
341}
342
343#[cfg(test)]
344mod tests;