bacnet_objects/device/
audit_recipient.rs1use super::*;
3use alloc::sync::Weak;
4use bacnet_types::constructed::{BACnetAddress, BACnetRecipient};
5
6#[doc(hidden)]
8#[derive(Clone)]
9pub struct AuditWriteSource {
10 pub device: BACnetRecipient,
11 pub invoke_id: u8,
12}
13
14#[doc(hidden)]
17pub trait AuditRecipientChangeSink: Send + Sync {
18 fn change(
19 &self,
20 current: &mut BACnetRecipient,
21 new: BACnetRecipient,
22 source: Option<&AuditWriteSource>,
23 clock: Option<ClockFrame>,
24 ) -> Result<(), Error>;
25 fn is_active(&self) -> bool;
26}
27
28#[derive(Default)]
29pub(super) struct RecipientState {
30 value: Option<BACnetRecipient>,
31 sink: Option<Weak<dyn AuditRecipientChangeSink>>,
32}
33
34fn property_error(code: ErrorCode) -> Error {
35 Error::protocol(ErrorClass::PROPERTY, code)
36}
37
38#[doc(hidden)]
41pub struct DeviceAuthority<'a>(pub(super) &'a mut DeviceObject);
42
43impl DeviceAuthority<'_> {
44 pub fn object_identifier(&self) -> ObjectIdentifier {
45 self.0.oid
46 }
47 pub fn set_services_supported(&mut self, services: &[ServiceSupported]) {
48 self.0.set_services_supported(services);
49 }
50 pub fn set_object_list(&mut self, oids: Vec<ObjectIdentifier>) {
51 self.0.set_object_list(oids);
52 }
53 pub fn set_system_status(&mut self, status: DeviceStatus) {
54 self.0.set_system_status(status);
55 }
56 pub fn set_database_revision(&mut self, revision: u32) {
57 self.0.set_database_revision(revision);
58 }
59 pub fn set_backup_and_restore_state(&mut self, state: BackupAndRestoreState) {
60 self.0.set_backup_and_restore_state(state);
61 }
62 pub fn set_last_restore_time(&mut self, time: BACnetTimeStamp) {
63 self.0.set_last_restore_time(time);
64 }
65 pub fn set_configuration_files(&mut self, files: Vec<ObjectIdentifier>) {
66 self.0.set_configuration_files(files);
67 }
68 pub fn write_property(
69 &mut self,
70 property: PropertyIdentifier,
71 index: Option<u32>,
72 value: PropertyValue,
73 priority: Option<u8>,
74 ) -> Result<(), Error> {
75 self.0.write_property(property, index, value, priority)
76 }
77 pub fn provision_audit_recipient(&mut self, recipient: BACnetRecipient) -> Result<(), Error> {
78 self.0.provision_audit_recipient(recipient)
79 }
80 pub fn provisioned_audit_recipient(&self) -> Option<&BACnetRecipient> {
81 self.0.recipient.value.as_ref()
82 }
83 pub fn validate_audit_recipient_installation(&self) -> Result<(), Error> {
84 if self.0.recipient.value.is_none()
85 || self
86 .0
87 .recipient
88 .sink
89 .as_ref()
90 .and_then(Weak::upgrade)
91 .is_some()
92 {
93 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
94 }
95 Ok(())
96 }
97 pub fn install_audit_recipient(
98 &mut self,
99 sink: &Arc<dyn AuditRecipientChangeSink>,
100 ) -> Result<(), Error> {
101 self.validate_audit_recipient_installation()?;
102 self.0.recipient.sink = Some(Arc::downgrade(sink));
103 Ok(())
104 }
105 pub fn uninstall_audit_recipient(&mut self, sink: &Arc<dyn AuditRecipientChangeSink>) {
106 if !sink.is_active()
107 && self
108 .0
109 .recipient
110 .sink
111 .as_ref()
112 .and_then(Weak::upgrade)
113 .is_some_and(|current| Arc::ptr_eq(¤t, sink))
114 {
115 self.0.recipient.sink = None;
116 }
117 }
118 pub fn write_audit_recipient(
119 &mut self,
120 index: Option<u32>,
121 value: PropertyValue,
122 priority: Option<u8>,
123 source: Option<&AuditWriteSource>,
124 ) -> Result<(), Error> {
125 self.0.write_audit_recipient(index, value, priority, source)
126 }
127}
128
129impl DeviceObject {
130 pub fn provision_audit_recipient(&mut self, recipient: BACnetRecipient) -> Result<(), Error> {
134 validate_recipient(&recipient)?;
135 if self
136 .recipient
137 .sink
138 .as_ref()
139 .and_then(Weak::upgrade)
140 .is_some()
141 {
142 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
143 }
144 self.recipient.value = Some(recipient);
145 Ok(())
146 }
147
148 pub(super) fn audit_recipient_present(&self) -> bool {
149 self.recipient.value.is_some()
150 && self
151 .recipient
152 .sink
153 .as_ref()
154 .and_then(Weak::upgrade)
155 .is_some()
156 }
157
158 pub(super) fn read_audit_recipient(&self, index: Option<u32>) -> Result<PropertyValue, Error> {
159 if !self.audit_recipient_present() {
160 return Err(property_error(ErrorCode::UNKNOWN_PROPERTY));
161 }
162 if index.is_some() {
163 return Err(property_error(ErrorCode::PROPERTY_IS_NOT_AN_ARRAY));
164 }
165 let mut bytes = bytes::BytesMut::new();
166 bacnet_encoding::constructed::encode_recipient(
167 &mut bytes,
168 self.recipient.value.as_ref().expect("present"),
169 )?;
170 Ok(PropertyValue::ApplicationData(bytes.to_vec()))
171 }
172
173 pub(super) fn write_audit_recipient(
174 &mut self,
175 index: Option<u32>,
176 value: PropertyValue,
177 priority: Option<u8>,
178 source: Option<&AuditWriteSource>,
179 ) -> Result<(), Error> {
180 let sink = self
181 .recipient
182 .sink
183 .as_ref()
184 .and_then(Weak::upgrade)
185 .ok_or_else(|| property_error(ErrorCode::UNKNOWN_PROPERTY))?;
186 if !sink.is_active() {
187 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
188 }
189 if index.is_some() {
190 return Err(property_error(ErrorCode::PROPERTY_IS_NOT_AN_ARRAY));
191 }
192 if priority.is_some_and(|p| !(1..=16).contains(&p)) {
193 return Err(Error::protocol(
194 ErrorClass::SERVICES,
195 ErrorCode::PARAMETER_OUT_OF_RANGE,
196 ));
197 }
198 if value == PropertyValue::Null {
199 return Ok(());
200 }
201 let PropertyValue::ApplicationData(bytes) = value else {
202 return Err(property_error(ErrorCode::INVALID_DATA_TYPE));
203 };
204 let (new, end) = bacnet_encoding::constructed::decode_recipient(&bytes, 0)
205 .map_err(|_| property_error(ErrorCode::INVALID_DATA_ENCODING))?;
206 if end != bytes.len() {
207 return Err(property_error(ErrorCode::INVALID_DATA_ENCODING));
208 }
209 validate_recipient(&new)?;
210 let clock = self.clock_frame();
211 let current = self.recipient.value.as_mut().expect("installed recipient");
212 if *current == new {
213 return Ok(());
214 }
215 sink.change(current, new, source, clock)
216 }
217}
218
219fn validate_recipient(recipient: &BACnetRecipient) -> Result<(), Error> {
223 match recipient {
224 BACnetRecipient::Device(oid)
225 if oid.object_type() != ObjectType::DEVICE
226 || oid.instance_number() == ObjectIdentifier::MAX_INSTANCE =>
227 {
228 Err(property_error(ErrorCode::INVALID_DATA_ENCODING))
229 }
230 BACnetRecipient::Address(address)
231 if address.mac_address.len() > BACnetAddress::MAX_MAC_LEN =>
232 {
233 Err(property_error(ErrorCode::INVALID_DATA_ENCODING))
234 }
235 _ => Ok(()),
236 }
237}