Skip to main content

bacnet_objects/audit/
reporter_object.rs

1//! Reporter property projection, separated to keep audit.rs within the LOC cap.
2
3use super::*;
4
5impl BACnetObject for AuditReporterObject {
6    fn audit_reporter_internal(&self) -> Option<&AuditReporterObject> {
7        Some(self)
8    }
9
10    fn configure_audit_reporter_internal(
11        &mut self,
12        level: AuditLevel,
13        operations: AuditOperationFlags,
14        confirmed: bool,
15        selectors: Option<Vec<BACnetObjectSelector>>,
16        priorities: BACnetPriorityFilter,
17        maximum_send_delay: Option<crate::audit::AuditSendDelay>,
18    ) -> Result<(), Error> {
19        let mut next = self.configuration_internal();
20        next.audit_level = level;
21        next.auditable_operations = operations;
22        next.confirmed = confirmed;
23        next.monitored_objects = selectors;
24        next.audit_priority_filter = priorities;
25        next.maximum_send_delay = maximum_send_delay;
26        self.change_configuration(next, None)
27    }
28
29    fn audit_reporter_authority_internal(&mut self) -> Option<AuditReporterAuthority<'_>> {
30        Some(AuditReporterAuthority(self))
31    }
32    fn bind_clock_internal(&mut self, clock: Option<Arc<dyn ClockReader>>) {
33        self.clock = clock;
34    }
35
36    fn object_identifier(&self) -> ObjectIdentifier {
37        self.oid
38    }
39
40    fn object_name(&self) -> &str {
41        &self.name
42    }
43
44    fn property_metadata(&self) -> Cow<'_, [PropertyMetadata]> {
45        reporter_metadata::effective_properties(
46            self.configuration_internal().monitored_objects.is_some(),
47            self.configuration_internal().maximum_send_delay.is_some(),
48        )
49    }
50
51    fn read_property(
52        &self,
53        property: PropertyIdentifier,
54        array_index: Option<u32>,
55    ) -> Result<PropertyValue, Error> {
56        let configuration = self.configuration_internal();
57        match property {
58            p if p == PropertyIdentifier::OBJECT_IDENTIFIER => {
59                Ok(PropertyValue::ObjectIdentifier(self.oid))
60            }
61            p if p == PropertyIdentifier::OBJECT_NAME => {
62                Ok(PropertyValue::CharacterString(self.name.clone()))
63            }
64            p if p == PropertyIdentifier::DESCRIPTION => Ok(PropertyValue::CharacterString(
65                configuration.description.clone(),
66            )),
67            p if p == PropertyIdentifier::OBJECT_TYPE => Ok(PropertyValue::Enumerated(
68                ObjectType::AUDIT_REPORTER.to_raw(),
69            )),
70            p if p == PropertyIdentifier::STATUS_FLAGS => Ok(PropertyValue::BitString {
71                unused_bits: 4,
72                data: vec![if self.reliability() == Reliability::NO_FAULT_DETECTED {
73                    0
74                } else {
75                    0x40
76                }],
77            }),
78            p if p == PropertyIdentifier::RELIABILITY => {
79                Ok(PropertyValue::Enumerated(self.reliability().to_raw()))
80            }
81            p if p == PropertyIdentifier::EVENT_STATE => {
82                Ok(PropertyValue::Enumerated(EventState::NORMAL.to_raw()))
83            }
84            p if p == PropertyIdentifier::AUDIT_LEVEL => Ok(PropertyValue::Enumerated(
85                configuration.audit_level.to_raw(),
86            )),
87            p if p == PropertyIdentifier::AUDIT_SOURCE_REPORTER => {
88                Ok(PropertyValue::Boolean(false))
89            }
90            p if p == PropertyIdentifier::AUDITABLE_OPERATIONS => {
91                let (unused_bits, data) = configuration.auditable_operations.to_bacnet();
92                Ok(PropertyValue::BitString { unused_bits, data })
93            }
94            p if p == PropertyIdentifier::AUDIT_PRIORITY_FILTER => {
95                let (unused_bits, data) = configuration.audit_priority_filter.to_bacnet();
96                Ok(PropertyValue::BitString { unused_bits, data })
97            }
98            p if p == PropertyIdentifier::ISSUE_CONFIRMED_NOTIFICATIONS => {
99                Ok(PropertyValue::Boolean(self.status.confirmed()))
100            }
101            p if p == PropertyIdentifier::MONITORED_OBJECTS
102                && configuration.monitored_objects.is_some() =>
103            {
104                let selectors = configuration
105                    .monitored_objects
106                    .as_ref()
107                    .expect("presence checked");
108                match array_index {
109                    None => Ok(PropertyValue::List(
110                        selectors
111                            .iter()
112                            .map(BACnetObjectSelector::encode_property_value)
113                            .collect(),
114                    )),
115                    Some(0) => Ok(PropertyValue::Unsigned(selectors.len() as u64)),
116                    Some(index) => selectors
117                        .get((index - 1) as usize)
118                        .map(BACnetObjectSelector::encode_property_value)
119                        .ok_or_else(crate::common::invalid_array_index_error),
120                }
121            }
122            p if matches!(
123                p,
124                PropertyIdentifier::MAXIMUM_SEND_DELAY | PropertyIdentifier::SEND_NOW
125            ) && configuration.maximum_send_delay.is_some() =>
126            {
127                if array_index.is_some() {
128                    return Err(crate::common::property_is_not_an_array_error());
129                }
130                if p == PropertyIdentifier::SEND_NOW {
131                    Ok(PropertyValue::Boolean(self.status.send_now()))
132                } else {
133                    Ok(PropertyValue::Unsigned(u64::from(
134                        configuration.maximum_send_delay.unwrap().seconds(),
135                    )))
136                }
137            }
138            p if p == PropertyIdentifier::PROPERTY_LIST => {
139                read_property_list_property(&self.property_list(), array_index)
140            }
141            _ => Err(Error::Protocol {
142                class: ErrorClass::PROPERTY.to_raw() as u32,
143                code: ErrorCode::UNKNOWN_PROPERTY.to_raw() as u32,
144            }),
145        }
146    }
147
148    fn write_property(
149        &mut self,
150        property: PropertyIdentifier,
151        array_index: Option<u32>,
152        value: PropertyValue,
153        _priority: Option<u8>,
154    ) -> Result<(), Error> {
155        if matches!(
156            property,
157            PropertyIdentifier::DESCRIPTION
158                | PropertyIdentifier::MAXIMUM_SEND_DELAY
159                | PropertyIdentifier::SEND_NOW
160        ) {
161            return AuditReporterAuthority(self).write_property(property, value, array_index, None);
162        }
163        Err(crate::common::unhandled_write_error(
164            self.property_metadata().as_ref(),
165            property,
166            array_index,
167        ))
168    }
169
170    fn property_list(&self) -> Cow<'static, [PropertyIdentifier]> {
171        crate::property_metadata::property_list_from_metadata(&self.property_metadata())
172    }
173}
174
175#[cfg(test)]
176#[path = "source_reporter_tests.rs"]
177mod source_reporter_tests;