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