bacnet_objects/device/
audit_recipient.rs1use super::*;
3use bacnet_types::constructed::{BACnetAddress, BACnetRecipient};
4use std::sync::Weak;
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 {
36 class: ErrorClass::PROPERTY.to_raw() as u32,
37 code: code.to_raw() as u32,
38 }
39}
40
41#[doc(hidden)]
44pub struct DeviceAuthority<'a>(pub(super) &'a mut DeviceObject);
45
46impl DeviceAuthority<'_> {
47 pub fn object_identifier(&self) -> ObjectIdentifier {
48 self.0.oid
49 }
50 pub fn set_services_supported(&mut self, services: &[ServiceSupported]) {
51 self.0.set_services_supported(services);
52 }
53 pub fn write_property(
54 &mut self,
55 property: PropertyIdentifier,
56 index: Option<u32>,
57 value: PropertyValue,
58 priority: Option<u8>,
59 ) -> Result<(), Error> {
60 self.0.write_property(property, index, value, priority)
61 }
62 pub fn provision_audit_recipient(&mut self, recipient: BACnetRecipient) -> Result<(), Error> {
63 self.0.provision_audit_recipient(recipient)
64 }
65 pub fn provisioned_audit_recipient(&self) -> Option<&BACnetRecipient> {
66 self.0.recipient.value.as_ref()
67 }
68 pub fn validate_audit_recipient_installation(&self) -> Result<(), Error> {
69 if self.0.recipient.value.is_none()
70 || self
71 .0
72 .recipient
73 .sink
74 .as_ref()
75 .and_then(Weak::upgrade)
76 .is_some()
77 {
78 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
79 }
80 Ok(())
81 }
82 pub fn install_audit_recipient(
83 &mut self,
84 sink: &Arc<dyn AuditRecipientChangeSink>,
85 ) -> Result<(), Error> {
86 self.validate_audit_recipient_installation()?;
87 self.0.recipient.sink = Some(Arc::downgrade(sink));
88 Ok(())
89 }
90 pub fn uninstall_audit_recipient(&mut self, sink: &Arc<dyn AuditRecipientChangeSink>) {
91 if !sink.is_active()
92 && self
93 .0
94 .recipient
95 .sink
96 .as_ref()
97 .and_then(Weak::upgrade)
98 .is_some_and(|current| Arc::ptr_eq(¤t, sink))
99 {
100 self.0.recipient.sink = None;
101 }
102 }
103 pub fn write_audit_recipient(
104 &mut self,
105 index: Option<u32>,
106 value: PropertyValue,
107 priority: Option<u8>,
108 source: Option<&AuditWriteSource>,
109 ) -> Result<(), Error> {
110 self.0.write_audit_recipient(index, value, priority, source)
111 }
112}
113
114impl DeviceObject {
115 pub fn provision_audit_recipient(&mut self, recipient: BACnetRecipient) -> Result<(), Error> {
119 validate_recipient(&recipient)?;
120 if self
121 .recipient
122 .sink
123 .as_ref()
124 .and_then(Weak::upgrade)
125 .is_some()
126 {
127 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
128 }
129 self.recipient.value = Some(recipient);
130 Ok(())
131 }
132
133 pub(super) fn audit_recipient_present(&self) -> bool {
134 self.recipient.value.is_some()
135 && self
136 .recipient
137 .sink
138 .as_ref()
139 .and_then(Weak::upgrade)
140 .is_some()
141 }
142
143 pub(super) fn read_audit_recipient(&self, index: Option<u32>) -> Result<PropertyValue, Error> {
144 if !self.audit_recipient_present() {
145 return Err(property_error(ErrorCode::UNKNOWN_PROPERTY));
146 }
147 if index.is_some() {
148 return Err(property_error(ErrorCode::PROPERTY_IS_NOT_AN_ARRAY));
149 }
150 let mut bytes = bytes::BytesMut::new();
151 bacnet_encoding::constructed::encode_recipient(
152 &mut bytes,
153 self.recipient.value.as_ref().expect("present"),
154 )?;
155 Ok(PropertyValue::ApplicationData(bytes.to_vec()))
156 }
157
158 pub(super) fn write_audit_recipient(
159 &mut self,
160 index: Option<u32>,
161 value: PropertyValue,
162 priority: Option<u8>,
163 source: Option<&AuditWriteSource>,
164 ) -> Result<(), Error> {
165 let sink = self
166 .recipient
167 .sink
168 .as_ref()
169 .and_then(Weak::upgrade)
170 .ok_or_else(|| property_error(ErrorCode::UNKNOWN_PROPERTY))?;
171 if !sink.is_active() {
172 return Err(property_error(ErrorCode::WRITE_ACCESS_DENIED));
173 }
174 if index.is_some() {
175 return Err(property_error(ErrorCode::PROPERTY_IS_NOT_AN_ARRAY));
176 }
177 if priority.is_some_and(|p| !(1..=16).contains(&p)) {
178 return Err(Error::Protocol {
179 class: ErrorClass::SERVICES.to_raw() as u32,
180 code: ErrorCode::PARAMETER_OUT_OF_RANGE.to_raw() as u32,
181 });
182 }
183 if value == PropertyValue::Null {
184 return Ok(());
185 }
186 let PropertyValue::ApplicationData(bytes) = value else {
187 return Err(property_error(ErrorCode::INVALID_DATA_TYPE));
188 };
189 let (new, end) = bacnet_encoding::constructed::decode_recipient(&bytes, 0)
190 .map_err(|_| property_error(ErrorCode::INVALID_DATA_ENCODING))?;
191 if end != bytes.len() {
192 return Err(property_error(ErrorCode::INVALID_DATA_ENCODING));
193 }
194 validate_recipient(&new)?;
195 let clock = self.clock_frame();
196 let current = self.recipient.value.as_mut().expect("installed recipient");
197 if *current == new {
198 return Ok(());
199 }
200 sink.change(current, new, source, clock)
201 }
202}
203
204fn validate_recipient(recipient: &BACnetRecipient) -> Result<(), Error> {
208 match recipient {
209 BACnetRecipient::Device(oid)
210 if oid.object_type() != ObjectType::DEVICE
211 || oid.instance_number() == ObjectIdentifier::MAX_INSTANCE =>
212 {
213 Err(property_error(ErrorCode::INVALID_DATA_ENCODING))
214 }
215 BACnetRecipient::Address(address)
216 if address.mac_address.len() > BACnetAddress::MAX_MAC_LEN =>
217 {
218 Err(property_error(ErrorCode::INVALID_DATA_ENCODING))
219 }
220 _ => Ok(()),
221 }
222}