Skip to main content

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 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)] // AFIT - Async Function In Trait
56pub 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)] // AFIT - Async Function In Trait
65pub 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    /// Returns the socket back to the caller and consumes self
109    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        // send packet until we get a reply
125        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        // receive reply
132        for _ in 0..5 {
133
134            match self.io.read(buf).await{
135                Ok(n) => {
136
137                    let buf = &buf[..n];
138
139                    // use the DataLink codec to decode the bytes
140                    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    /*
304    #[maybe_async()]
305    #[cfg_attr(feature = "alloc", bacnet_macros::remove_lifetimes_from_fn_args)]
306    async fn send_and_receive_complex_ack<'a>(
307        &self,
308        buf: &'a mut [u8],
309        service: ConfirmedRequestService<'_>,
310        addr: Option<NetworkAddress>,
311    ) -> Result<ComplexAck<'a>, BacnetError<T>> {
312        
313        let invoke_id = self.send_confirmed(buf, service, addr).await?;
314
315        loop {
316            // receive reply
317            let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
318            let buf = &buf[..n];
319
320            // use the DataLink codec to decode the bytes
321            let mut reader = Reader::default();
322            let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
323
324            match message.npdu {
325                Some(x) => match x.network_message {
326                    NetworkMessage::Apdu(ApplicationPdu::ComplexAck(ack)) => {
327                        // ignore earier messages
328                        if ack.invoke_id < invoke_id {
329                            continue;
330                        }
331
332                        // return message is expected to have the same invoke_id as the request (return error if later invoke id)
333                        Self::check_invoke_id(invoke_id, ack.invoke_id)?;
334                        return Ok(ack);
335                    }
336                    _ => continue,
337                },
338                _ => continue,
339            }
340        }
341    }
342    */  
343
344    #[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            // receive reply
358            let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
359            let buf = &buf[..n];
360
361            // use the DataLink codec to decode the bytes
362            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                        // ignore earier messages
369                        if ack.invoke_id < invoke_id {
370                            continue;
371                        }
372
373                        // return message is expected to have the same invoke_id as the request (return error if later invoke id)
374                        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        // receive reply
397        let n = self.io.read(buf).await.map_err(BacnetError::Io)?;
398        let buf = &buf[..n];
399
400        // use the DataLink codec to decode the bytes
401        let mut reader = Reader::default();
402        let message = DataLink::decode(&mut reader, buf).map_err(BacnetError::Codec)?;
403
404        // TODO: return bacnet error if the server returns one
405        // return message is expected to be a ComplexAck
406        let ack: SimpleAck = message.try_into().map_err(BacnetError::Codec)?;
407
408        // return message is expected to have the same invoke_id as the request
409        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        // send packet
429        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        // send packet
457        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}