Skip to main content

bacnet_services/
audit.rs

1//! Audit notification and query wire models.
2//!
3//! These codecs follow the corrected 2020 baseline: ANSI/ASHRAE 135-2020 plus
4//! the Errata Summary 2024-04-29 (v1), visually verified from the rendered
5//! errata page 3 under its page-1 convention (strikeout = removed, italics =
6//! added) and recorded by RB-01. Item 7 (Clause 21.6, printed p. 886)
7//! corrects the by-target/by-source `successful-actions-only` fields from
8//! BOOLEAN to `BACnetSuccessFilter` at unchanged tags \[7\]/\[4\]; item 8
9//! (Clause 21.2.3, printed p. 865) corrects `start-at-sequence-number` from
10//! Unsigned32 to Unsigned64 at unchanged optional tag \[2\]. Unsigned values
11//! use the library's `u64` implementation limit (1-8 octet canonical forms).
12
13#[cfg(not(feature = "std"))]
14use alloc::vec::Vec;
15
16pub use bacnet_types::constructed::{
17    AuditPropertyReference, BACnetAuditLogDatum, BACnetAuditLogQueryParameters,
18    BACnetAuditLogRecord, BACnetAuditLogRecordResult, BACnetAuditNotification,
19};
20use bacnet_types::error::Error;
21use bacnet_types::primitives::ObjectIdentifier;
22use bytes::BytesMut;
23
24#[path = "audit/notification_codec.rs"]
25mod notification_codec;
26#[path = "audit/query_ack_codec.rs"]
27mod query_ack_codec;
28#[path = "audit/query_codec.rs"]
29mod query_codec;
30
31/// Parameters shared by confirmed and unconfirmed AuditNotification.
32#[derive(Debug, Clone, PartialEq)]
33pub struct AuditNotificationRequest {
34    /// One or more notifications, encoded under context tag `[0]`.
35    pub notifications: Vec<BACnetAuditNotification>,
36}
37
38/// AuditLogQuery-ACK service parameters.
39///
40/// This wire model does not perform storage queries or infer record ordering,
41/// continuity, filtering, or the truth of `no_more_items`.
42#[derive(Debug, Clone, PartialEq)]
43pub struct AuditLogQueryAck {
44    /// Audit Log object whose records were queried.
45    pub audit_log: ObjectIdentifier,
46    /// Zero or more adjacent record results encoded under context tag `[1]`.
47    pub records: Vec<BACnetAuditLogRecordResult>,
48    /// `true` when no records remain beyond those returned; the codec does not verify it.
49    pub no_more_items: bool,
50}
51
52/// AuditLogQuery-Request service parameters.
53#[derive(Debug, Clone, PartialEq, Eq)]
54pub struct AuditLogQueryRequest {
55    /// Audit Log object to query.
56    pub audit_log: ObjectIdentifier,
57    /// Filter selecting which records to return.
58    pub query_parameters: BACnetAuditLogQueryParameters,
59    /// Corrected-baseline `Unsigned64` cursor (Errata 2024-04-29 item 8).
60    pub start_at_sequence_number: Option<u64>,
61    /// Maximum number of records the requester wants returned.
62    pub requested_count: u16,
63}
64
65impl AuditNotificationRequest {
66    /// Encode after validation, leaving `buf` unchanged on failure.
67    pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
68        notification_codec::encode(self, buf)
69    }
70
71    /// Encode the request into `buf`; same as `try_encode`.
72    pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
73        self.try_encode(buf)
74    }
75
76    /// Decode a complete payload; trailing bytes are rejected.
77    pub fn decode(data: &[u8]) -> Result<Self, Error> {
78        notification_codec::decode(data)
79    }
80}
81
82impl AuditLogQueryRequest {
83    /// Encode after validation, leaving `buf` unchanged on failure.
84    pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
85        query_codec::encode(self, buf)
86    }
87
88    /// Encode the request into `buf`; same as `try_encode`.
89    pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
90        self.try_encode(buf)
91    }
92
93    /// Decode a complete payload; trailing bytes are rejected.
94    pub fn decode(data: &[u8]) -> Result<Self, Error> {
95        query_codec::decode(data)
96    }
97}
98
99impl AuditLogQueryAck {
100    /// Encode after validation, leaving `buf` unchanged on failure.
101    pub fn try_encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
102        query_ack_codec::encode(self, buf)
103    }
104
105    /// Encode the ACK into `buf`; same as `try_encode`.
106    pub fn encode(&self, buf: &mut BytesMut) -> Result<(), Error> {
107        self.try_encode(buf)
108    }
109
110    /// Decode a complete payload; trailing bytes are rejected.
111    pub fn decode(data: &[u8]) -> Result<Self, Error> {
112        query_ack_codec::decode(data)
113    }
114}
115
116#[cfg(test)]
117#[path = "audit/tests.rs"]
118mod tests;
119
120#[cfg(test)]
121#[path = "audit/malformed_tests.rs"]
122mod malformed_tests;
123
124#[cfg(test)]
125#[path = "audit/empty_value_tests.rs"]
126mod empty_value_tests;
127
128#[cfg(test)]
129#[path = "audit/address_bound_tests.rs"]
130mod address_bound_tests;