1use core::{
9 fmt::Debug,
10 sync::atomic::{AtomicU8, Ordering},
11};
12
13use maybe_async::maybe_async;
14
15use crate::{
16 application_protocol::{
17 application_pdu::ApplicationPdu,
18 confirmed::{
19 ComplexAck, ComplexAckService, ConfirmedRequest, ConfirmedRequestService, SimpleAck,
20 },
21 services::{
22 change_of_value::{CovNotification, SubscribeCov},
23 i_am::IAm,
24 read_property::{ReadProperty, ReadPropertyAck},
25 read_property_multiple::{ReadPropertyMultiple, ReadPropertyMultipleAck},
26 read_range::{ReadRange, ReadRangeAck},
27 time_synchronization::TimeSynchronization,
28 who_is::WhoIs,
29 write_property::WriteProperty,
30 },
31 unconfirmed::UnconfirmedRequest,
32 },
33 common::{
34 error::Error,
35 io::{Reader, Writer},
36 },
37 network_protocol::{
38 data_link::{DataLink, DataLinkFunction},
39 network_pdu::{DestinationAddress, MessagePriority, NetworkAddress, NetworkMessage, NetworkPdu},
40 },
41};
42
43#[derive(Debug)]
44pub struct Bacnet<T>
45where
46 T: NetworkIo + Debug,
47{
48 pub io: T,
49 invoke_id: AtomicU8,
50}
51
52#[allow(async_fn_in_trait)]
53#[cfg(feature = "defmt")]
54#[maybe_async(AFIT)] pub trait NetworkIo {
56 type Error: Debug + defmt::Format;
57 async fn read(&self, buf: &mut [u8]) -> Result<usize, Self::Error>;
58 async fn write(&self, buf: &[u8]) -> Result<usize, Self::Error>;
59}
60
61#[cfg(not(feature = "defmt"))]
62#[allow(async_fn_in_trait)]
63#[maybe_async(AFIT)] pub trait NetworkIo {
65 type Error: Debug;
66
67 async fn read(&self, buf: &mut [u8]) -> Result<usize, Self::Error>;
68 async fn write(&self, buf: &[u8]) -> Result<usize, Self::Error>;
69 async fn disconnect(&self) -> Result<bool, Self::Error>;
70}
71
72#[derive(Debug)]
73#[cfg_attr(feature = "defmt", derive(defmt::Format))]
74pub enum BacnetError<T>
75where
76 T: NetworkIo,
77{
78 Io(T::Error),
79 Codec(Error),
80 InvokeId(InvokeIdError),
81}
82
83impl<T: NetworkIo> From<Error> for BacnetError<T> {
84 fn from(value: Error) -> Self {
85 Self::Codec(value)
86 }
87}
88
89#[derive(Debug)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub struct InvokeIdError {
92 pub expected: u8,
93 pub actual: u8,
94}
95
96impl<T> Bacnet<T>
97where
98 T: NetworkIo + Debug,
99{
100 pub fn new(io: T) -> Self {
101 Self {
102 io,
103 invoke_id: AtomicU8::new(0),
104 }
105 }
106
107 pub fn into_inner(self) -> T {
109 self.io
110 }
111
112 #[maybe_async()]
113 pub async fn who_is(&self, buf: &mut [u8]) -> Result<Option<IAm>, BacnetError<T>> {
114 let apdu = ApplicationPdu::UnconfirmedRequest(UnconfirmedRequest::WhoIs(WhoIs {}));
115 let dst = Some(DestinationAddress::new(0xffff, None));
116 let message = NetworkMessage::Apdu(apdu);
117 let npdu = NetworkPdu::new(None, dst, false, MessagePriority::Normal, message);
118 let data_link = DataLink::new(DataLinkFunction::OriginalBroadcastNpdu, Some(npdu));
119
120 let mut writer = Writer::new(buf);
121 data_link.encode(&mut writer);
122
123 let buffer = writer.to_bytes();
125
126 self.io.write(buffer).await.map_err(BacnetError::Io)?;
127
128 for _ in 0..2 {
130 let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
131 let buf = &buf[..n];
132
133 let mut reader = Reader::default();
135 let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
136
137 if let Some(npdu) = message.npdu {
138
139 if let Some(dst_src) = npdu.src {
140
141 if let NetworkMessage::Apdu(ApplicationPdu::UnconfirmedRequest(
142 UnconfirmedRequest::IAm(iam),
143 )) = npdu.network_message
144 {
145 let mut iam = iam.clone();
146 iam.dst_addr = Some(dst_src);
147
148 return Ok(Some(iam));
149 }
150
151 }
152 };
153 }
154
155 Ok(None)
156 }
157
158 #[maybe_async()]
159 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
160 pub async fn read_property_multiple<'a>(
161 &self,
162 buf: &'a mut [u8],
163 request: ReadPropertyMultiple<'_>,
164 addr: Option<NetworkAddress>,
165 ) -> Result<ReadPropertyMultipleAck<'a>, BacnetError<T>> {
166
167 let service = ConfirmedRequestService::ReadPropertyMultiple(request);
168
169 if let Some(ack) = self.send_and_receive_complex_ack(buf, service, addr).await? {
170 match ack.service {
171 ComplexAckService::ReadPropertyMultiple(ack) => Ok(ack),
172 _ => Err(BacnetError::Codec(Error::ConvertDataLink(
173 "apdu message is not a ComplexAckService ReadPropertyMultipleAck",
174 ))),
175 }
176 } else {
177 Err(BacnetError::Codec(Error::ConvertDataLink(
178 "apdu message is not a ComplexAckService ReadPropertyMultipleAck",
179 )))
180 }
181 }
182
183 #[maybe_async()]
184 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
185 pub async fn read_property<'a>(
186 &self,
187 buf: &'a mut [u8],
188 request: ReadProperty,
189 addr: Option<NetworkAddress>,
190 ) -> Result<ReadPropertyAck<'a>, BacnetError<T>> {
191
192 let service = ConfirmedRequestService::ReadProperty(request);
193
194 if let Some(ack) = self.send_and_receive_complex_ack(buf, service, addr).await? {
195
196 match ack.service {
197 ComplexAckService::ReadProperty(ack) => Ok(ack),
198 _ => Err(BacnetError::Codec(Error::ConvertDataLink(
199 "apdu message is not a ComplexAckService ReadPropertyAck",
200 ))),
201 }
202 } else {
203 Err(BacnetError::Codec(Error::ConvertDataLink(
204 "apdu message is not a ComplexAckService ReadPropertyAck",
205 )))
206 }
207 }
208
209 #[maybe_async()]
210 pub async fn subscribe_change_of_value(
211 &self,
212 buf: &mut [u8],
213 request: SubscribeCov,
214 ) -> Result<(), BacnetError<T>> {
215 let service = ConfirmedRequestService::SubscribeCov(request);
216 let _ack = self.send_and_receive_simple_ack(buf, service, None).await?;
217 Ok(())
218 }
219
220 #[maybe_async()]
221 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
222 pub async fn read_change_of_value<'a>(
223 &self,
224 buf: &'a mut [u8],
225 ) -> Result<Option<CovNotification<'a>>, BacnetError<T>> {
226 let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
227 let mut reader = Reader::default();
228 let message = DataLink::decode(&mut reader, &buf[..n])?;
229
230 if let Some(npdu) = message.npdu {
231 if let NetworkMessage::Apdu(ApplicationPdu::UnconfirmedRequest(
232 UnconfirmedRequest::CovNotification(x),
233 )) = npdu.network_message
234 {
235 return Ok(Some(x));
236 }
237 };
238
239 Ok(None)
240 }
241
242 #[maybe_async()]
243 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
244 pub async fn read_range<'a>(
245 &self,
246 buf: &'a mut [u8],
247 request: ReadRange,
248 ) -> Result<ReadRangeAck<'a>, BacnetError<T>> {
249 let service = ConfirmedRequestService::ReadRange(request);
250
251 if let Some(ack) = self.send_and_receive_complex_ack(buf, service, None).await? {
252
253 match ack.service {
254 ComplexAckService::ReadRange(ack) => Ok(ack),
255 _ => Err(BacnetError::Codec(Error::ConvertDataLink(
256 "apdu message is not a ComplexAckService ReadRangeAck",
257 ))),
258 }
259
260 } else {
261 Err(BacnetError::Codec(Error::ConvertDataLink(
262 "apdu message is not a ComplexAckService ReadRangeAck",
263 )))
264
265 }
266 }
267
268 #[maybe_async()]
269 pub async fn write_property<'a>(
270 &self,
271 buf: &mut [u8],
272 request: WriteProperty<'_>,
273 addr: Option<NetworkAddress>,
274 ) -> Result<(), BacnetError<T>> {
275 let service = ConfirmedRequestService::WriteProperty(request);
276 let _ack = self.send_and_receive_simple_ack(buf, service, addr).await?;
277 Ok(())
278 }
279
280 #[maybe_async()]
281 pub async fn time_sync(
282 &self,
283 buf: &mut [u8],
284 request: TimeSynchronization,
285 ) -> Result<(), BacnetError<T>> {
286 let service = UnconfirmedRequest::TimeSynchronization(request);
287 self.send_unconfirmed(buf, service).await
288 }
289
290 #[maybe_async()]
332 #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
333 async fn send_and_receive_complex_ack<'a>(
334 &self,
335 buf: &'a mut [u8],
336 service: ConfirmedRequestService<'_>,
337 addr: Option<NetworkAddress>,
338 ) -> Result<Option<ComplexAck<'a>>, BacnetError<T>> {
339
340 let invoke_id = self.send_confirmed(buf, service, addr).await?;
341
342 for _ in 1..3 {
343
344 let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
346 let buf = &buf[..n];
347
348 let mut reader = Reader::default();
350 let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
351
352 match message.npdu {
353 Some(x) => match x.network_message {
354 NetworkMessage::Apdu(ApplicationPdu::ComplexAck(ack)) => {
355 if ack.invoke_id < invoke_id {
357 continue;
358 }
359
360 Self::check_invoke_id(invoke_id, ack.invoke_id)?;
362 return Ok(Some(ack));
363 }
364 _ => continue,
365 },
366 _ => continue,
367 }
368 }
369
370 Ok(None)
371 }
372
373
374 #[maybe_async()]
375 async fn send_and_receive_simple_ack<'a>(
376 &self,
377 buf: &mut [u8],
378 service: ConfirmedRequestService<'_>,
379 addr: Option<NetworkAddress>,
380 ) -> Result<SimpleAck, BacnetError<T>> {
381 let invoke_id = self.send_confirmed(buf, service, addr).await?;
382
383 let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
385 let buf = &buf[..n];
386
387 let mut reader = Reader::default();
389 let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
390
391 let ack: SimpleAck = message.try_into().map_err(BacnetError::Codec)?;
394
395 Self::check_invoke_id(invoke_id, ack.invoke_id)?;
397
398 Ok(ack)
399 }
400
401 #[maybe_async()]
402 async fn send_unconfirmed(
403 &self,
404 buf: &mut [u8],
405 service: UnconfirmedRequest<'_>,
406 ) -> Result<(), BacnetError<T>> {
407 let apdu = ApplicationPdu::UnconfirmedRequest(service);
408 let message = NetworkMessage::Apdu(apdu);
409 let npdu = NetworkPdu::new(None, None, true, MessagePriority::Normal, message);
410 let data_link = DataLink::new(DataLinkFunction::OriginalUnicastNpdu, Some(npdu));
411
412 let mut writer = Writer::new(buf);
413 data_link.encode(&mut writer);
414
415 let buffer = writer.to_bytes();
417 self.io.write(buffer).await.map_err(BacnetError::Io)?;
418 Ok(())
419 }
420
421 #[maybe_async()]
422 async fn send_confirmed(
423 &self,
424 buf: &mut [u8],
425 service: ConfirmedRequestService<'_>,
426 addr: Option<NetworkAddress>,
427 ) -> Result<u8, BacnetError<T>> {
428
429 let mut dst: Option<DestinationAddress> = None;
430
431 if let Some(addr) = addr {
432 dst = Some(DestinationAddress::new(addr.net, addr.addr));
433 }
434 let invoke_id = self.get_then_inc_invoke_id();
435 let apdu = ApplicationPdu::ConfirmedRequest(ConfirmedRequest::new(invoke_id, service));
436 let message = NetworkMessage::Apdu(apdu);
437 let npdu = NetworkPdu::new(None, dst, true, MessagePriority::Normal, message);
438 let data_link = DataLink::new(DataLinkFunction::OriginalUnicastNpdu, Some(npdu));
439
440 let mut writer = Writer::new(buf);
441 data_link.encode(&mut writer);
442
443 let buffer = writer.to_bytes();
445 self.io.write(buffer).await.map_err(BacnetError::Io)?;
446
447 Ok(invoke_id)
448 }
449
450 fn check_invoke_id(expected: u8, actual: u8) -> Result<(), BacnetError<T>> {
451 if expected != actual {
452 Err(BacnetError::InvokeId(InvokeIdError { expected, actual }))
453 } else {
454 Ok(())
455 }
456 }
457
458 fn get_then_inc_invoke_id(&self) -> u8 {
459 self.invoke_id.fetch_add(1, Ordering::SeqCst)
460 }
461}