bacnet_npdu/lib.rs
1//! The BACnet network-layer vocabulary (Clause 6), in one place, for every
2//! layer of rusty-bacnet and for firmware.
3//!
4//! The crate is `no_std`, needs no allocator and has no dependencies. It
5//! holds what the portable cores, the hosted transports and network layer,
6//! and the owned codec of `bacnet-encoding` all speak, so each concept has
7//! one definition:
8//!
9//! - [`Npdu`]: a borrowed view of an NPDU's control information and its
10//! payload. [`Npdu::decode`] reads one in place, telling an address too
11//! long for any data link ([`DecodeError::AddressTooLong`]) apart from
12//! every other fault ([`Malformed`]); [`Npdu::encoded_len`] and
13//! [`Npdu::encode_into`] write one into the caller's buffer, refusing
14//! anything the decoder would refuse before writing an octet.
15//! - [`NetworkMessageType`] and [`RejectMessageReason`]: the open sets of
16//! wire codes for network-layer messages and their reject reasons.
17//! - [`RejectMessageToNetwork`]: a reject's data, its reason and network,
18//! read and written in place, refused with [`RejectLengthError`] when it
19//! isn't three octets.
20//! - [`NetworkPriority`]: the closed, two-bit network priority.
21//! - [`NpduLimits`]: the longest NPDU a link carries each way, and
22//! [`MAX_NPDU`], the longest any data link here carries.
23//! - [`Mac`]: a link-layer address of up to [`MAX_MAC_LEN`] octets, stored
24//! inline.
25//!
26//! The other network-layer messages' payloads, the routing table and the
27//! router itself are `bacnet-router-core`'s.
28//!
29//! # Example
30//!
31//! ```
32//! use bacnet_npdu::{Address, Npdu, NetworkPriority};
33//!
34//! // A confirmed request for station 5 on network 2, at urgent priority.
35//! let mut request = Npdu::apdu(&[0x00, 0x05, 0x01, 0x0C]);
36//! request.destination = Some(Address { network: 2, mac: &[5] });
37//! request.expecting_reply = true;
38//! request.priority = NetworkPriority::Urgent;
39//!
40//! let mut frame = [0u8; 32];
41//! let len = request.encode_into(&mut frame)?;
42//! assert_eq!(len, request.encoded_len());
43//! assert_eq!(&frame[..len], &[0x01, 0x25, 0x00, 0x02, 0x01, 0x05, 0xFF, 0x00, 0x05, 0x01, 0x0C]);
44//!
45//! let decoded = Npdu::decode(&frame[..len]).expect("an NPDU");
46//! assert_eq!(decoded.destination, request.destination);
47//! assert_eq!(decoded.priority, NetworkPriority::Urgent);
48//! assert_eq!(decoded.payload, request.payload);
49//! # Ok::<(), Box<dyn core::error::Error>>(())
50//! ```
51
52#![no_std]
53#![forbid(unsafe_code)]
54#![cfg_attr(docsrs, feature(doc_cfg))]
55#![warn(missing_debug_implementations)]
56#![warn(clippy::must_use_candidate)]
57
58mod codes;
59mod encode;
60mod limits;
61mod mac;
62mod priority;
63mod reject;
64mod view;
65
66pub use codes::{NetworkMessageType, RejectMessageReason};
67pub use encode::EncodeError;
68pub use limits::NpduLimits;
69pub use mac::{Mac, MacTooLong};
70pub use priority::{NetworkPriority, PriorityError};
71pub use reject::{RejectLengthError, RejectMessageToNetwork};
72pub use view::{Address, AddressField, DecodeError, Malformed, Npdu};
73
74/// The protocol version every NPDU starts with.
75pub const VERSION: u8 = 1;
76
77/// The DNET of a global broadcast.
78pub const GLOBAL_NETWORK: u16 = 0xFFFF;
79
80/// The longest NPDU, in octets, that B/IP, B/IPv6, Ethernet and MS/TP with
81/// extended frames carry (Table 6-1; Clause 9.3 for MS/TP).
82pub const MAX_NPDU: usize = 1497;
83
84const _: () = assert!(MAX_NPDU <= u16::MAX as usize, "NpduLimits holds MAX_NPDU");
85
86/// The longest DADR, SADR or link MAC the stack accepts, in octets (#1141).
87///
88/// A length octet could announce up to 255. No standard data link in
89/// Table 6-2 needs more than 7 (a LonTalk Neuron_ID destination), and the
90/// links this stack serves address a node in at most 6: 1 for MS/TP, 3 for
91/// B/IPv6 (its VMAC, Annex U.1.3) and 6 for B/IP, Ethernet and BACnet/SC.
92/// The bound is 18, the length of the IPv6 address and port the stack once
93/// used as the B/IPv6 MAC: a defensive ceiling, which lets a router carry a
94/// non-standard MAC through unchanged, and which stays where it is by
95/// decision (#1673).
96///
97/// [`Npdu::decode`] refuses a longer DLEN or SLEN, [`Npdu::encode_into`]
98/// a longer DADR or SADR, and [`Mac`] holds no more.
99pub const MAX_MAC_LEN: usize = 18;
100
101/// The README's example, compiled and run as a doctest.
102#[cfg(doctest)]
103#[doc = include_str!("../README.md")]
104pub struct ReadmeDoctests;