Skip to main content

bacnet_client/client/
cov_target.rs

1//! [`CovTarget`]: the device a managed COV subscription goes to (#1790).
2
3use super::*;
4
5/// The device a managed COV subscription goes to: on this network at a MAC,
6/// or on another network behind a router.
7///
8/// A device keeps a subscription under the address the request came from
9/// (Clause 13.14.2), and its notifications carry that subscription's process
10/// identifier back from the device's own address (Clauses 13.6.1 and
11/// 13.7.1). So a notification belongs to this target when it comes from the
12/// same address: the MAC with no source network for a local device, or the
13/// source network and station address for a routed one. The router a
14/// routed notification came through is not part of the device's address and
15/// isn't compared.
16#[derive(Debug, Clone, PartialEq, Eq, Hash)]
17#[non_exhaustive]
18pub enum CovTarget {
19    /// A device on this network.
20    Local {
21        /// Its MAC address.
22        mac: MacAddr,
23    },
24    /// A device on another network, reached through a router on this one.
25    Routed {
26        /// The MAC of the router the requests go to.
27        router_mac: MacAddr,
28        /// The device's network number, 1 to 65534.
29        network: u16,
30        /// The device's MAC address on that network.
31        address: MacAddr,
32    },
33}
34
35impl CovTarget {
36    /// A device on this network at `mac`.
37    pub fn local(mac: &[u8]) -> Self {
38        Self::Local {
39            mac: MacAddr::from_slice(mac),
40        }
41    }
42
43    /// A device at `address` on `network`, reached through the router at
44    /// `router_mac`.
45    pub fn routed(router_mac: &[u8], network: u16, address: &[u8]) -> Self {
46        Self::Routed {
47            router_mac: MacAddr::from_slice(router_mac),
48            network,
49            address: MacAddr::from_slice(address),
50        }
51    }
52
53    /// Where a discovered device is: routed when its I-Am came with a source
54    /// network and address (through the router it came from), local
55    /// otherwise.
56    pub fn of_device(device: &DiscoveredDevice) -> Self {
57        match (device.source_network, &device.source_address) {
58            (Some(network), Some(address)) => Self::Routed {
59                router_mac: device.mac_address.clone(),
60                network,
61                address: address.clone(),
62            },
63            _ => Self::Local {
64                mac: device.mac_address.clone(),
65            },
66        }
67    }
68
69    pub(super) fn confirmed(&self) -> ConfirmedTarget<'_> {
70        match self {
71            Self::Local { mac } => ConfirmedTarget::Local { mac },
72            Self::Routed {
73                router_mac,
74                network,
75                address,
76            } => ConfirmedTarget::Routed {
77                router_mac,
78                dest_network: *network,
79                dest_mac: address,
80            },
81        }
82    }
83
84    /// True when `received` came from this device's address. A routed
85    /// target on the client's own network (`local_network`, once learned)
86    /// is sent to as a local device (#1358), so its notifications may come
87    /// with no source network, from its address as the MAC.
88    pub(super) fn sent(
89        &self,
90        received: &ReceivedCOVNotification,
91        local_network: Option<u16>,
92    ) -> bool {
93        let local_from = |mac: &MacAddr| {
94            received.source_network.is_none()
95                && received.source_address.is_none()
96                && received.source_mac == *mac
97        };
98        match self {
99            Self::Local { mac } => local_from(mac),
100            Self::Routed {
101                network, address, ..
102            } => {
103                (received.source_network == Some(*network)
104                    && received.source_address.as_ref() == Some(address))
105                    || (local_network == Some(*network) && local_from(address))
106            }
107        }
108    }
109}