1use super::*;
2
3fn validate_atomic_read_file_ack(
4 request: &bacnet_services::file::FileAccessMethod,
5 ack: &bacnet_services::file::AtomicReadFileAck,
6) -> Result<(), Error> {
7 use bacnet_services::file::{FileAccessMethod, FileReadAckMethod};
8
9 match (request, &ack.access) {
10 (
11 FileAccessMethod::Stream {
12 requested_octet_count,
13 ..
14 },
15 FileReadAckMethod::Stream { file_data, .. },
16 ) if file_data.len() <= *requested_octet_count as usize => Ok(()),
17 (FileAccessMethod::Stream { .. }, FileReadAckMethod::Stream { .. }) => Err(
18 Error::decoding(0, "AtomicReadFile ACK exceeds the requested octet window"),
19 ),
20 (
21 FileAccessMethod::Record {
22 requested_record_count,
23 ..
24 },
25 FileReadAckMethod::Record {
26 returned_record_count,
27 file_record_data,
28 ..
29 },
30 ) if returned_record_count <= requested_record_count
31 && *returned_record_count as usize == file_record_data.len() =>
32 {
33 Ok(())
34 }
35 (FileAccessMethod::Record { .. }, FileReadAckMethod::Record { .. }) => Err(
36 Error::decoding(0, "AtomicReadFile ACK exceeds the requested record window"),
37 ),
38 _ => Err(Error::decoding(
39 0,
40 "AtomicReadFile ACK access method does not match the request",
41 )),
42 }
43}
44
45impl<T: TransportPort + 'static> BACnetClient<T> {
46 pub async fn get_event_information(
48 &self,
49 destination_mac: &[u8],
50 last_received_object_identifier: Option<bacnet_types::primitives::ObjectIdentifier>,
51 ) -> Result<Bytes, Error> {
52 use bacnet_services::alarm_event::GetEventInformationRequest;
53
54 let request = GetEventInformationRequest {
55 last_received_object_identifier,
56 };
57 let mut buf = BytesMut::new();
58 request.encode(&mut buf);
59
60 self.confirmed_request(
61 destination_mac,
62 ConfirmedServiceChoice::GET_EVENT_INFORMATION,
63 &buf,
64 )
65 .await
66 }
67
68 pub async fn acknowledge_alarm_request(
70 &self,
71 destination_mac: &[u8],
72 request: &bacnet_services::alarm_event::AcknowledgeAlarmRequest,
73 ) -> Result<(), Error> {
74 let mut buf = BytesMut::new();
75 request.encode(&mut buf)?;
76
77 let _ = self
78 .confirmed_request(
79 destination_mac,
80 ConfirmedServiceChoice::ACKNOWLEDGE_ALARM,
81 &buf,
82 )
83 .await?;
84
85 Ok(())
86 }
87
88 #[deprecated(
95 note = "use acknowledge_alarm_request with caller-supplied correlation timestamps"
96 )]
97 pub async fn acknowledge_alarm(
98 &self,
99 destination_mac: &[u8],
100 acknowledging_process_identifier: u32,
101 event_object_identifier: bacnet_types::primitives::ObjectIdentifier,
102 event_state_acknowledged: bacnet_types::enums::EventState,
103 acknowledgment_source: &str,
104 ) -> Result<(), Error> {
105 use bacnet_services::alarm_event::AcknowledgeAlarmRequest;
106
107 let request = AcknowledgeAlarmRequest {
108 acknowledging_process_identifier,
109 event_object_identifier,
110 event_state_acknowledged,
111 timestamp: bacnet_types::primitives::BACnetTimeStamp::SequenceNumber(0),
112 acknowledgment_source: acknowledgment_source.to_string(),
113 time_of_acknowledgment: bacnet_types::primitives::BACnetTimeStamp::SequenceNumber(0),
114 };
115 self.acknowledge_alarm_request(destination_mac, &request)
116 .await
117 }
118
119 pub async fn atomic_read_file(
121 &self,
122 destination_mac: &[u8],
123 file_identifier: bacnet_types::primitives::ObjectIdentifier,
124 access: bacnet_services::file::FileAccessMethod,
125 ) -> Result<Bytes, Error> {
126 use bacnet_services::file::AtomicReadFileRequest;
127
128 let request = AtomicReadFileRequest {
129 file_identifier,
130 access,
131 };
132 let mut buf = BytesMut::new();
133 request.encode(&mut buf);
134
135 self.confirmed_request(
136 destination_mac,
137 ConfirmedServiceChoice::ATOMIC_READ_FILE,
138 &buf,
139 )
140 .await
141 }
142
143 pub async fn atomic_read_file_decoded(
150 &self,
151 destination_mac: &[u8],
152 file_identifier: bacnet_types::primitives::ObjectIdentifier,
153 access: bacnet_services::file::FileAccessMethod,
154 ) -> Result<bacnet_services::file::AtomicReadFileAck, Error> {
155 let requested_access = access.clone();
156 let response = self
157 .atomic_read_file(destination_mac, file_identifier, access)
158 .await?;
159 let ack = bacnet_services::file::AtomicReadFileAck::decode(&response)?;
160 validate_atomic_read_file_ack(&requested_access, &ack)?;
161 Ok(ack)
162 }
163
164 pub async fn atomic_write_file(
166 &self,
167 destination_mac: &[u8],
168 file_identifier: bacnet_types::primitives::ObjectIdentifier,
169 access: bacnet_services::file::FileWriteAccessMethod,
170 ) -> Result<Bytes, Error> {
171 use bacnet_services::file::AtomicWriteFileRequest;
172
173 let request = AtomicWriteFileRequest {
174 file_identifier,
175 access,
176 };
177 let mut buf = BytesMut::new();
178 request.encode(&mut buf);
179
180 self.confirmed_request(
181 destination_mac,
182 ConfirmedServiceChoice::ATOMIC_WRITE_FILE,
183 &buf,
184 )
185 .await
186 }
187
188 pub async fn add_list_element(
193 &self,
194 destination_mac: &[u8],
195 object_identifier: bacnet_types::primitives::ObjectIdentifier,
196 property_identifier: bacnet_types::enums::PropertyIdentifier,
197 property_array_index: Option<u32>,
198 list_of_elements: Vec<u8>,
199 ) -> Result<(), Error> {
200 use bacnet_services::list_manipulation::ListElementRequest;
201
202 let request = ListElementRequest {
203 object_identifier,
204 property_identifier,
205 property_array_index,
206 list_of_elements,
207 };
208 let mut buf = BytesMut::new();
209 request.encode(&mut buf)?;
210
211 let _ = self
212 .confirmed_request(
213 destination_mac,
214 ConfirmedServiceChoice::ADD_LIST_ELEMENT,
215 &buf,
216 )
217 .await?;
218
219 Ok(())
220 }
221
222 pub async fn remove_list_element(
227 &self,
228 destination_mac: &[u8],
229 object_identifier: bacnet_types::primitives::ObjectIdentifier,
230 property_identifier: bacnet_types::enums::PropertyIdentifier,
231 property_array_index: Option<u32>,
232 list_of_elements: Vec<u8>,
233 ) -> Result<(), Error> {
234 use bacnet_services::list_manipulation::ListElementRequest;
235
236 let request = ListElementRequest {
237 object_identifier,
238 property_identifier,
239 property_array_index,
240 list_of_elements,
241 };
242 let mut buf = BytesMut::new();
243 request.encode(&mut buf)?;
244
245 let _ = self
246 .confirmed_request(
247 destination_mac,
248 ConfirmedServiceChoice::REMOVE_LIST_ELEMENT,
249 &buf,
250 )
251 .await?;
252
253 Ok(())
254 }
255}
256
257#[cfg(test)]
258#[path = "file_list_decoded_tests.rs"]
259mod decoded_tests;