Skip to main content

Crate bacnet_bip_codec

Crate bacnet_bip_codec 

Source
Expand description

An allocation-free codec for BACnet/IP BVLL messages, on IPv4 (Annex J) at the crate root and on IPv6 (Annex U) in ipv6.

The crate covers the wire format and nothing above it. For B/IP that is the 4-octet BVLL header, the twelve messages Annex J.2 defines, six-octet B/IP addresses (J.1.2), and the entries of BDTs and FDTs; ipv6 does the same for the twelve messages of Annex U.2, with B/IPv6 addresses and virtual MAC addresses. Sockets, BBMD forwarding, the foreign-device registration lifecycle and which device answers what belong to the layer that uses it. Both message families share the BvllSink trait and the header constants.

The default build never allocates. Bvll borrows its NPDU or table from the datagram, tables are read through iterators (Entries::iter), and Bvll::encode_into writes into caller storage. Only the optional alloc and bytes sinks grow on the heap.

§Validation

Decoding is strict about shape and lenient about values. BvllFrame::decode requires BVLC type 0x81 and a Length field equal to the datagram’s length: the field counts the whole message (J.2), so a truncated datagram and one with trailing octets are both refused. BvllFrame::message then requires a function J.2 defines and a payload of the length its format clause gives (see BvlcFunction::payload_shape). It does not judge field values: an undefined result code, a zero time-to-live, any table entry and an empty NPDU all decode, and the receiver decides what to do with them. decode runs both steps.

Function 0x0C is unknown here: the clause that once defined it (J.2.13) is deleted in this edition.

Encoding is checked. A Bvll variant holds exactly its function’s fields, so most malformed shapes can’t be built; Bvll::encoded_len also refuses a message longer than the Length field can state and a BVLC-Result with a code J.2.1.1 doesn’t define.

§Addresses

A B/IP address is a plain SocketAddrV4, and address_to_octets, address_from_octets and address_from_slice convert it to and from its six wire octets. Every field of a SocketAddrV4 travels, so a type of its own would add nothing. B/IPv6 does get one, ipv6::Bip6Address: a SocketAddrV6 also holds a flow label and a scope ID, which never go on the wire, and the type keeps only the 18 octets that do.

§Features

No feature needs std. Each adds a BvllSink implementation, which both encoders use:

  • alloc: for alloc::vec::Vec<u8>.
  • bytes: for bytes::BytesMut; implies alloc.
  • heapless: for heapless::Vec<u8, N>.

§Example

use bacnet_bip_codec::{decode, Bvll, BvllError, BvlcFunction};

let npdu = [0x01, 0x20, 0xFF, 0xFF, 0x00, 0xFF];
let message = Bvll::OriginalBroadcastNpdu(&npdu);
let mut wire = [0u8; 64];
let length = message.encode_into(&mut wire)?;
assert_eq!(wire[..4], [0x81, 0x0B, 0x00, 0x0A]);

let decoded = decode(&wire[..length])?;
assert_eq!(decoded, message);
assert_eq!(decoded.function(), BvlcFunction::ORIGINAL_BROADCAST_NPDU);
assert_eq!(decoded.npdu(), Some(&npdu[..]));

Modules§

ipv6
The B/IPv6 BVLL codec: BACnet/IPv6 messages (Annex U).

Structs§

BdtEntry
One row of a broadcast distribution table: a BBMD’s B/IP address and the broadcast distribution mask that says how to reach its subnet (Annex J.2.2.1, J.4.3.2).
BvlcFunction
A BVLC function code: the second octet of every B/IP BVLL message, which says what the message is (Annex J.2).
BvlcResultCode
The result code a BVLC-Result carries (Annex J.2.1.1): success, or a NAK naming the request that failed.
BvllFrame
A BVLL message whose header checks out, before its payload is read.
Entries
A table carried in a BVLL payload, borrowed rather than copied: either the wire octets of a decoded message, or entries a caller wants to encode. Both read the same through Entries::iter, and two tables compare equal when their entries do.
EntryIter
Iterator over a table’s entries; see Entries::iter.
FdtEntry
One row of a foreign device table as Read-Foreign-Device-Table-Ack returns it (Annex J.2.8.1): the registrant’s B/IP address, the time-to-live it registered with, and the seconds left before the BBMD purges it, which include the 30-second grace period of J.5.2.3.
SinkFull
A BvllSink had no room for a write.

Enums§

Bvll
One B/IP BVLL message (Annex J.2), borrowing its NPDU or table.
BvllError
A BVLL message could not be decoded or encoded.
PayloadShape
How long the payload of a BVLL message may be: the octets after the 4-octet header, which depend on the function alone (Annex J.2, U.2).

Constants§

BDT_ENTRY_LENGTH
Octets in a broadcast distribution table entry: B/IP address and mask (Annex J.2.2.1).
BIP_ADDRESS_LENGTH
Octets in a B/IP address: IPv4 address and UDP port (Annex J.1.2).
BVLC_TYPE_BIP
The BVLC Type octet of a B/IP message (Annex J.2).
DEFAULT_PORT
The default UDP port, 47808 (0xBAC0), for B/IP and B/IPv6 alike (Annex J.1.2, U.1.1.2).
FDT_ENTRY_LENGTH
Octets in a foreign device table entry: B/IP address, time-to-live and seconds remaining (Annex J.2.8.1).
HEADER_LENGTH
The BVLL header: type, function and the two Length octets. B/IP and B/IPv6 share it (Annex J.2, U.2).
MAX_BVLL_LENGTH
The largest message the 16-bit Length field can state, header included, in either annex.

Traits§

BvllSink
A destination for encoded BVLL octets, shared by the B/IP and the B/IPv6 encoders.
TableEntry
A table entry type: BdtEntry or FdtEntry. Sealed.

Functions§

address_from_octets
The B/IP address six octets hold (Annex J.1.2).
address_from_slice
The B/IP address in octets, which must be exactly six octets long.
address_to_octets
The six octets of a B/IP address: the IPv4 address, then the UDP port, both most significant octet first (Annex J.1.2).
decode
Decode one datagram as a BVLL message: BvllFrame::decode, then BvllFrame::message.

Type Aliases§

BdtEntries
A broadcast distribution table (Annex J.2.2.1, J.2.4.1).
FdtEntries
A foreign device table (Annex J.2.8.1).