bacnet_emb/simple/
mod.rs

1/// This module is meant to be a very basic way to interact with a BACnet IP network in a simple request / response manner
2/// It automatically links up requests with responses using an invoke_id which only really works when you send one request at a time.
3/// If you intend to fire off many simultaneous requests then you should keep track of invoke_ids and handle congestion and packet ordering yourself.
4/// Your NetworkIo implementation is responsible for timeout detection for reads and writes.
5/// This is an async-first module but you can run it in a native blocking way if you like.
6///   The `maybe_async` crate is used to avoid code duplication and completely stips away async code when the `is_sync` feature flag is set.
7/// If you are having trouble with the borrow checker try enabling the `alloc` feature to make BACnet objects fully owned
8use 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)] // AFIT - Async Function In Trait
55pub 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)] // AFIT - Async Function In Trait
64pub 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    /// Returns the socket back to the caller and consumes self
108    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        // send packet until we get a reply
124        let buffer = writer.to_bytes();
125
126        self.io.write(buffer).await.map_err(BacnetError::Io)?;
127
128        // receive reply
129        for _ in 0..2 {
130            let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
131            let buf = &buf[..n];
132
133            // use the DataLink codec to decode the bytes
134            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    /*
291    #[maybe_async()]
292    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
293    async fn send_and_receive_complex_ack<'a>(
294        &self,
295        buf: &'a mut [u8],
296        service: ConfirmedRequestService<'_>,
297        addr: Option<NetworkAddress>,
298    ) -> Result<ComplexAck<'a>, BacnetError<T>> {
299        
300        let invoke_id = self.send_confirmed(buf, service, addr).await?;
301
302        loop {
303            // receive reply
304            let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
305            let buf = &buf[..n];
306
307            // use the DataLink codec to decode the bytes
308            let mut reader = Reader::default();
309            let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
310
311            match message.npdu {
312                Some(x) => match x.network_message {
313                    NetworkMessage::Apdu(ApplicationPdu::ComplexAck(ack)) => {
314                        // ignore earier messages
315                        if ack.invoke_id < invoke_id {
316                            continue;
317                        }
318
319                        // return message is expected to have the same invoke_id as the request (return error if later invoke id)
320                        Self::check_invoke_id(invoke_id, ack.invoke_id)?;
321                        return Ok(ack);
322                    }
323                    _ => continue,
324                },
325                _ => continue,
326            }
327        }
328    }
329    */  
330
331    #[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            // receive reply
345            let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
346            let buf = &buf[..n];
347
348            // use the DataLink codec to decode the bytes
349            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                        // ignore earier messages
356                        if ack.invoke_id < invoke_id {
357                            continue;
358                        }
359
360                        // return message is expected to have the same invoke_id as the request (return error if later invoke id)
361                        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        // receive reply
384        let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
385        let buf = &buf[..n];
386
387        // use the DataLink codec to decode the bytes
388        let mut reader = Reader::default();
389        let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
390
391        // TODO: return bacnet error if the server returns one
392        // return message is expected to be a ComplexAck
393        let ack: SimpleAck = message.try_into().map_err(BacnetError::Codec)?;
394
395        // return message is expected to have the same invoke_id as the request
396        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        // send packet
416        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        // send packet
444        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}