bacnet_ops/engine/
discover.rs1use bacnet_client::client::{DeviceEvent, DiscoveredRouter};
5use bacnet_client::discovery::DiscoveredDevice;
6use bacnet_services::who_is::{DeviceInstanceRange, WhoIsRequest};
7use bacnet_transport::port::TransportPort;
8use bacnet_types::enums::UnconfirmedServiceChoice;
9use bacnet_types::error::Error;
10use bytes::BytesMut;
11
12use super::Engine;
13use crate::target::{self, AddressStyle};
14
15const NOT_A_STATION: &str =
17 "a directed Who-Is needs a station address, not a device instance or routed target";
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum WhoIsScope<'a> {
22 Local,
24 Network(u16),
26 Directed(&'a str),
29 Global,
31}
32
33impl<T: TransportPort + 'static> Engine<T> {
34 pub async fn who_is(
38 &self,
39 scope: WhoIsScope<'_>,
40 range: Option<DeviceInstanceRange>,
41 ) -> Result<(), Error> {
42 let mac = match scope {
43 WhoIsScope::Directed(address) => Some(
44 target::address_mac(self.client.transport(), address, NOT_A_STATION)
45 .await
46 .map_err(Error::Encoding)?,
47 ),
48 _ => None,
49 };
50 let network = match scope {
54 WhoIsScope::Local | WhoIsScope::Directed(_) => Some(0),
55 WhoIsScope::Network(network) => Some(network),
56 WhoIsScope::Global => None,
57 };
58 self.limits.slot(network).await;
59 let sent = match (scope, mac) {
60 (WhoIsScope::Local, _) => {
61 let mut buf = BytesMut::new();
62 WhoIsRequest { range }.encode(&mut buf);
63 self.client
64 .broadcast_unconfirmed(UnconfirmedServiceChoice::WHO_IS, &buf)
65 .await
66 }
67 (WhoIsScope::Network(network), _) => self.client.who_is_network(network, range).await,
68 (WhoIsScope::Directed(_), Some(mac)) => self.client.who_is_directed(&mac, range).await,
69 (WhoIsScope::Directed(_), None) => unreachable!("a directed Who-Is has its address"),
70 (WhoIsScope::Global, _) => self.client.who_is(range).await,
71 };
72 if sent.is_err() {
75 crate::limits::refund();
76 }
77 sent
78 }
79
80 pub async fn discover_routers(
87 &self,
88 network: Option<u16>,
89 wait: std::time::Duration,
90 deadline: Option<tokio::time::Instant>,
91 ) -> Result<Vec<DiscoveredRouter>, Error> {
92 self.limits.slot(Some(0)).await;
93 let wait = match deadline {
94 Some(deadline) => {
95 wait.min(deadline.saturating_duration_since(tokio::time::Instant::now()))
96 }
97 None => wait,
98 };
99 let found = self.client.discover_routers(network, wait).await;
100
101 if found.is_err() {
103 crate::limits::refund();
104 }
105 found
106 }
107
108 pub async fn station_mac(&self, address: &str) -> Result<Vec<u8>, Error> {
112 target::address_mac(self.client.transport(), address, NOT_A_STATION)
113 .await
114 .map_err(Error::Encoding)
115 }
116
117 pub async fn devices(&self) -> Vec<DiscoveredDevice> {
119 self.client.discovered_devices().await
120 }
121
122 pub async fn device(&self, instance: u32) -> Option<DiscoveredDevice> {
124 self.client.get_device(instance).await
125 }
126
127 pub fn device_events(&self) -> tokio::sync::broadcast::Receiver<DeviceEvent> {
131 self.client.device_events()
132 }
133
134 pub fn address_style(&self) -> AddressStyle {
136 AddressStyle::of(self.client.transport())
137 }
138}