Skip to main content

bacnet_client/client/
event_notifications.rs

1use super::*;
2use bacnet_encoding::constructed::decode_event_notification_tolerant;
3use bacnet_services::alarm_event::EventNotificationRequest;
4
5/// Default event notification broadcast channel capacity, independent of COV.
6pub const DEFAULT_EVENT_CHANNEL_CAPACITY: usize = 64;
7
8/// Maximum event notification broadcast channel capacity accepted at startup.
9pub const MAX_EVENT_CHANNEL_CAPACITY: usize = 65_536;
10
11/// Delivery mode used for a received event notification.
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum EventNotificationDelivery {
14    /// Notification arrived as a ConfirmedEventNotification request.
15    Confirmed,
16    /// Notification arrived as an UnconfirmedEventNotification request.
17    Unconfirmed,
18}
19
20/// A decoded inbound event notification plus transport-observed metadata.
21#[derive(Debug, Clone)]
22pub struct ReceivedEventNotification {
23    /// Decoded service payload. Unsupported or invalid message text is discarded
24    /// as `None`; all other fields retain the shared decoder's validation.
25    pub notification: EventNotificationRequest,
26    /// Immediate transport source MAC that delivered the NPDU.
27    pub source_mac: MacAddr,
28    /// NPDU source network, when supplied by a routed sender.
29    pub source_network: Option<u16>,
30    /// NPDU source MAC/address, when supplied by a routed sender.
31    pub source_address: Option<MacAddr>,
32    /// Whether the notification used the confirmed or unconfirmed service.
33    pub delivery: EventNotificationDelivery,
34}
35
36impl ReceivedEventNotification {
37    fn decode(
38        data: &[u8],
39        source_mac: &[u8],
40        source_network: &Option<NpduAddress>,
41        delivery: EventNotificationDelivery,
42    ) -> Result<Self, Error> {
43        let notification = decode_event_notification_tolerant(data)?;
44        let (network, address) = match source_network {
45            Some(source) if !source.mac_address.is_empty() => {
46                (Some(source.network), Some(source.mac_address.clone()))
47            }
48            _ => (None, None),
49        };
50        Ok(Self {
51            notification,
52            source_mac: MacAddr::from_slice(source_mac),
53            source_network: network,
54            source_address: address,
55            delivery,
56        })
57    }
58}
59
60impl ClientOptions {
61    /// Set the independent event notification channel capacity.
62    /// Values outside `1..=MAX_EVENT_CHANNEL_CAPACITY` fail at startup.
63    pub fn with_event_channel_capacity(mut self, capacity: usize) -> Self {
64        self.event_channel_capacity = capacity;
65        self
66    }
67}
68
69impl<T: TransportPort + 'static> BACnetClient<T> {
70    /// Subscribe to incoming event notifications with a new independent receiver.
71    ///
72    /// Only subsequent notifications are delivered. Slow receivers observe
73    /// broadcast lag; no receivers or lag never prevent a valid confirmed request
74    /// from being acknowledged. The wire acknowledgment confirms receipt, not
75    /// operator acknowledgment or durable application processing. Stopping the
76    /// client ends dispatch; dropping it closes the channel after queued messages.
77    pub fn event_notifications(&self) -> broadcast::Receiver<ReceivedEventNotification> {
78        self.event_tx.subscribe()
79    }
80
81    pub(super) async fn receive_confirmed_event_notification(
82        network: &Arc<NetworkLayer<T>>,
83        event_tx: &broadcast::Sender<ReceivedEventNotification>,
84        source_mac: &[u8],
85        source_network: &Option<NpduAddress>,
86        reply: InboundReply,
87        req: ConfirmedRequestPdu,
88        decode_warning: &WarnThrottle,
89    ) {
90        let received = match ReceivedEventNotification::decode(
91            &req.service_request,
92            source_mac,
93            source_network,
94            EventNotificationDelivery::Confirmed,
95        ) {
96            Ok(received) => received,
97            Err(error) => {
98                warn_throttled!(
99                    decode_warning,
100                    %error,
101                    "Failed to decode ConfirmedEventNotification"
102                );
103                // The reason names the syntax fault, as the server's does
104                // for any confirmed request (#1446).
105                let reject_reason = error
106                    .reject_reason()
107                    .unwrap_or(RejectReason::INVALID_DATA_ENCODING);
108                Self::send_confirmed_request_reject(
109                    network,
110                    source_mac,
111                    source_network,
112                    reply,
113                    req.invoke_id,
114                    reject_reason,
115                )
116                .await;
117                return;
118            }
119        };
120        let _ = event_tx.send(received);
121        let ack = Apdu::SimpleAck(SimpleAck {
122            invoke_id: req.invoke_id,
123            service_choice: req.service_choice,
124        });
125        let mut buf = BytesMut::with_capacity(3);
126        if let Err(error) = encode_apdu(&mut buf, &ack) {
127            warn!(%error, "Failed to encode event notification acknowledgment");
128            return;
129        }
130        if let Err(error) =
131            Self::send_received_reply_apdu(network, &buf, source_mac, source_network, reply).await
132        {
133            warn!(%error, "Failed to send event notification acknowledgment");
134        }
135    }
136}
137
138pub(super) fn receive_unconfirmed_event_notification(
139    event_tx: &broadcast::Sender<ReceivedEventNotification>,
140    source_mac: &[u8],
141    source_network: &Option<NpduAddress>,
142    data: &[u8],
143    decode_warning: &WarnThrottle,
144) {
145    match ReceivedEventNotification::decode(
146        data,
147        source_mac,
148        source_network,
149        EventNotificationDelivery::Unconfirmed,
150    ) {
151        Ok(received) => {
152            let _ = event_tx.send(received);
153        }
154        Err(error) => {
155            warn_throttled!(
156                decode_warning,
157                %error,
158                "Failed to decode UnconfirmedEventNotification"
159            );
160        }
161    }
162}