1use super::*;
2
3impl<T: TransportPort + 'static> BACnetClient<T> {
4 pub async fn confirmed_request(
10 &self,
11 destination_mac: &[u8],
12 service_choice: ConfirmedServiceChoice,
13 service_data: &[u8],
14 ) -> Result<Bytes, Error> {
15 self.confirmed_request_inner(
16 ConfirmedTarget::Local {
17 mac: destination_mac,
18 },
19 service_choice,
20 service_data,
21 )
22 .await
23 }
24
25 pub async fn confirmed_request_routed(
30 &self,
31 router_mac: &[u8],
32 dest_network: u16,
33 dest_mac: &[u8],
34 service_choice: ConfirmedServiceChoice,
35 service_data: &[u8],
36 ) -> Result<Bytes, Error> {
37 self.confirmed_request_inner(
38 ConfirmedTarget::Routed {
39 router_mac,
40 dest_network,
41 dest_mac,
42 },
43 service_choice,
44 service_data,
45 )
46 .await
47 }
48
49 pub(super) async fn confirmed_request_inner(
50 &self,
51 target: ConfirmedTarget<'_>,
52 service_choice: ConfirmedServiceChoice,
53 service_data: &[u8],
54 ) -> Result<Bytes, Error> {
55 let tsm_mac = target.tsm_mac();
56 let unsegmented_apdu_size = 4 + service_data.len();
57
58 match target {
59 ConfirmedTarget::Local { mac } => {
60 let (remote_max_apdu, remote_max_segments) = {
61 let dt = self.device_table.lock().await;
62 let device = dt.get_by_mac(mac);
63 let max_apdu = device
64 .map(|d| d.max_apdu_length as u16)
65 .unwrap_or(self.config.max_apdu_length);
66 let max_seg = device.and_then(|d| d.max_segments_accepted);
67 (max_apdu, max_seg)
68 };
69 if unsegmented_apdu_size > remote_max_apdu as usize {
70 return self
71 .segmented_confirmed_request(
72 target,
73 service_choice,
74 service_data,
75 remote_max_apdu,
76 remote_max_segments,
77 )
78 .await;
79 }
80 }
81 ConfirmedTarget::Routed { .. } => {
82 let remote_max_apdu = self.config.max_apdu_length;
83 if unsegmented_apdu_size > remote_max_apdu as usize {
84 return self
85 .segmented_confirmed_request(
86 target,
87 service_choice,
88 service_data,
89 remote_max_apdu,
90 None,
91 )
92 .await;
93 }
94 }
95 }
96
97 let (invoke_id, rx) = {
98 let mut tsm = self.tsm.lock().await;
99 let invoke_id = tsm.allocate_invoke_id(&tsm_mac).ok_or_else(|| {
100 Error::Encoding("all invoke IDs exhausted for destination".into())
101 })?;
102 let rx = tsm.register_transaction(tsm_mac.clone(), invoke_id);
103 (invoke_id, rx)
104 };
105
106 let mut guard =
108 crate::tsm::TsmGuard::new(std::sync::Arc::clone(&self.tsm), tsm_mac.clone(), invoke_id);
109
110 let pdu = Apdu::ConfirmedRequest(ConfirmedRequestPdu {
111 segmented: false,
112 more_follows: false,
113 segmented_response_accepted: self.config.segmented_response_accepted,
114 max_segments: self.config.max_segments,
115 max_apdu_length: self.config.max_apdu_length,
116 invoke_id,
117 sequence_number: None,
118 proposed_window_size: None,
119 service_choice,
120 service_request: Bytes::copy_from_slice(service_data),
121 });
122
123 let mut buf = BytesMut::with_capacity(6 + service_data.len());
124 encode_apdu(&mut buf, &pdu)?;
125
126 let timeout_duration = Duration::from_millis(self.config.apdu_timeout_ms);
127 let max_retries = self.config.apdu_retries;
128 let mut attempts: u8 = 0;
129 let mut rx = rx;
130
131 loop {
132 let send_result = match &target {
133 ConfirmedTarget::Local { mac } => {
134 self.network
135 .send_apdu(&buf, mac, true, NetworkPriority::NORMAL)
136 .await
137 }
138 ConfirmedTarget::Routed {
139 router_mac,
140 dest_network,
141 dest_mac,
142 } => {
143 self.network
144 .send_apdu_routed(
145 &buf,
146 *dest_network,
147 dest_mac,
148 router_mac,
149 true,
150 NetworkPriority::NORMAL,
151 )
152 .await
153 }
154 };
155 if let Err(e) = send_result {
156 guard.mark_completed();
157 let mut tsm = self.tsm.lock().await;
158 tsm.cancel_transaction(&tsm_mac, invoke_id);
159 return Err(e);
160 }
161
162 match timeout(timeout_duration, &mut rx).await {
163 Ok(Ok(response)) => {
164 guard.mark_completed();
165 return match response {
166 TsmResponse::SimpleAck => Ok(Bytes::new()),
167 TsmResponse::ComplexAck { service_data } => Ok(service_data),
168 TsmResponse::Error { class, code } => Err(Error::Protocol { class, code }),
169 TsmResponse::Reject { reason } => Err(Error::Reject { reason }),
170 TsmResponse::Abort { reason } => Err(Error::Abort { reason }),
171 };
172 }
173 Ok(Err(_)) => {
174 guard.mark_completed();
175 return Err(Error::Encoding("TSM response channel closed".into()));
176 }
177 Err(_timeout) => {
178 attempts += 1;
179 if attempts > max_retries {
180 guard.mark_completed();
181 let mut tsm = self.tsm.lock().await;
182 tsm.cancel_transaction(&tsm_mac, invoke_id);
183 return Err(Error::Timeout(timeout_duration));
184 }
185 debug!(
186 invoke_id,
187 attempt = attempts,
188 max_retries,
189 "APDU timeout, retrying confirmed request"
190 );
191 }
192 }
193 }
194 }
195
196 pub(super) async fn send_confirmed_target_apdu(
197 &self,
198 target: ConfirmedTarget<'_>,
199 apdu: &[u8],
200 ) -> Result<(), Error> {
201 match target {
202 ConfirmedTarget::Local { mac } => {
203 self.network
204 .send_apdu(apdu, mac, true, NetworkPriority::NORMAL)
205 .await
206 }
207 ConfirmedTarget::Routed {
208 router_mac,
209 dest_network,
210 dest_mac,
211 } => {
212 self.network
213 .send_apdu_routed(
214 apdu,
215 dest_network,
216 dest_mac,
217 router_mac,
218 true,
219 NetworkPriority::NORMAL,
220 )
221 .await
222 }
223 }
224 }
225 pub async fn unconfirmed_request(
227 &self,
228 destination_mac: &[u8],
229 service_choice: UnconfirmedServiceChoice,
230 service_data: &[u8],
231 ) -> Result<(), Error> {
232 let pdu = Apdu::UnconfirmedRequest(bacnet_encoding::apdu::UnconfirmedRequest {
233 service_choice,
234 service_request: Bytes::copy_from_slice(service_data),
235 });
236
237 let mut buf = BytesMut::with_capacity(2 + service_data.len());
238 encode_apdu(&mut buf, &pdu)?;
239
240 self.network
241 .send_apdu(&buf, destination_mac, false, NetworkPriority::NORMAL)
242 .await
243 }
244
245 pub async fn broadcast_unconfirmed(
247 &self,
248 service_choice: UnconfirmedServiceChoice,
249 service_data: &[u8],
250 ) -> Result<(), Error> {
251 let pdu = Apdu::UnconfirmedRequest(bacnet_encoding::apdu::UnconfirmedRequest {
252 service_choice,
253 service_request: Bytes::copy_from_slice(service_data),
254 });
255
256 let mut buf = BytesMut::with_capacity(2 + service_data.len());
257 encode_apdu(&mut buf, &pdu)?;
258
259 self.network
260 .broadcast_apdu(&buf, false, NetworkPriority::NORMAL)
261 .await
262 }
263
264 pub async fn broadcast_global_unconfirmed(
266 &self,
267 service_choice: UnconfirmedServiceChoice,
268 service_data: &[u8],
269 ) -> Result<(), Error> {
270 let pdu = Apdu::UnconfirmedRequest(bacnet_encoding::apdu::UnconfirmedRequest {
271 service_choice,
272 service_request: Bytes::copy_from_slice(service_data),
273 });
274
275 let mut buf = BytesMut::with_capacity(2 + service_data.len());
276 encode_apdu(&mut buf, &pdu)?;
277
278 self.network
279 .broadcast_global_apdu(&buf, false, NetworkPriority::NORMAL)
280 .await
281 }
282
283 pub async fn broadcast_network_unconfirmed(
285 &self,
286 service_choice: UnconfirmedServiceChoice,
287 service_data: &[u8],
288 dest_network: u16,
289 ) -> Result<(), Error> {
290 let pdu = Apdu::UnconfirmedRequest(bacnet_encoding::apdu::UnconfirmedRequest {
291 service_choice,
292 service_request: Bytes::copy_from_slice(service_data),
293 });
294
295 let mut buf = BytesMut::with_capacity(2 + service_data.len());
296 encode_apdu(&mut buf, &pdu)?;
297
298 self.network
299 .broadcast_to_network(&buf, dest_network, false, NetworkPriority::NORMAL)
300 .await
301 }
302}