bacnet_ops/engine/
bbmd.rs1use std::any::Any;
6use std::net::SocketAddrV4;
7
8use bacnet_transport::bip::{BipTransport, BvlcExchangeError};
9use bacnet_transport::port::TransportPort;
10
11use super::Engine;
12use crate::bbmd::{BdtRow, FdtRow, Outcome, Probe, mac};
13
14impl<T: TransportPort + 'static> Engine<T> {
15 pub fn bip(&self) -> Option<&BipTransport> {
17 (self.client.transport() as &dyn Any).downcast_ref()
18 }
19
20 pub fn registration_bbmd(&self) -> Option<SocketAddrV4> {
23 self.bip()?
24 .bvlc_client_snapshot()
25 .foreign_registration
26 .last_bbmd
27 }
28
29 pub async fn read_bdt(&self, bbmd: SocketAddrV4) -> Probe {
32 let Some(bip) = self.bip() else {
33 return Outcome::Unreachable(NOT_BIP.into());
34 };
35 self.limits.slot(Some(0)).await;
36 settle(bip.read_bdt(&mac(bbmd)).await, |e| BdtRow::from(e))
37 }
38
39 pub async fn read_fdt(&self, bbmd: SocketAddrV4) -> Outcome<Vec<FdtRow>> {
41 let Some(bip) = self.bip() else {
42 return Outcome::Unreachable(NOT_BIP.into());
43 };
44 self.limits.slot(Some(0)).await;
45 settle(bip.read_fdt(&mac(bbmd)).await, |e| FdtRow::from(e))
46 }
47}
48
49const NOT_BIP: &str = "BBMD tables need BACnet/IP";
51
52fn settle<E, R>(read: Result<Vec<E>, BvlcExchangeError>, row: fn(&E) -> R) -> Outcome<Vec<R>> {
55 match read {
56 Ok(entries) => Outcome::Table(entries.iter().map(row).collect()),
57 Err(error) => {
58 if matches!(error, BvlcExchangeError::Refused(_)) {
59 crate::limits::refund();
60 }
61 Outcome::from_error(&error)
62 }
63 }
64}