bacnet-bip-codec 0.13.0

Portable no-std BACnet/IP and BACnet/IPv6 (Annexes J and U) BVLL codec
Documentation

bacnet-bip-codec

The BVLL codec of rusty-bacnet: the wire format of BACnet/IP (Annex J of ASHRAE 135) at the crate root and of BACnet/IPv6 (Annex U) in its ipv6 module, and nothing above it. Sockets, BBMD forwarding and foreign-device registration belong to the layer that uses it, such as bacnet-bip-core.

  • #![no_std], no allocator and no dependencies in the default build.
  • The twelve B/IP messages and the twelve B/IPv6 ones, as Bvll and Bvll6 values that borrow their NPDU or table from the datagram.
  • Decoding is strict about shape (BVLC type, a Length field equal to the datagram, a payload the function's layout allows) and lenient about values; encoding refuses what the Length field can't state and a BVLC-Result with an undefined code.
  • BvlcFunction, BvlcResultCode and their B/IPv6 counterparts are open sets: a constant for each code the standard defines, and from_raw for any other, so a decoder can report a code it doesn't know.
  • BDT and FDT entries, read through iterators straight from the wire.
  • A B/IP address is a plain SocketAddrV4, since all of it travels; a B/IPv6 address is a Bip6Address, which keeps the 18 octets that travel and none of a SocketAddrV6's flow label or scope ID.

Features

None is on by default, and none needs std. Each adds a BvllSink, which both encoders write to:

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

Example

use core::net::{Ipv4Addr, SocketAddrV4};
use bacnet_bip_codec::{decode, BvlcFunction, Bvll, BvllFrame};

// Encode an Original-Broadcast-NPDU into caller storage.
let npdu = [0x01, 0x20, 0xFF, 0xFF, 0x00, 0xFF];
let mut wire = [0u8; 64];
let length = Bvll::OriginalBroadcastNpdu(&npdu).encode_into(&mut wire).unwrap();
assert_eq!(wire[..4], [0x81, 0x0B, 0x00, 0x0A]);
assert_eq!(decode(&wire[..length]), Ok(Bvll::OriginalBroadcastNpdu(&npdu)));

// A Forwarded-NPDU carries its originator's address.
let wire = [0x81, 0x04, 0x00, 0x0C, 192, 168, 1, 20, 0xBA, 0xC0, 0x01, 0x00];
let origin = SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 20), 47808);
assert_eq!(decode(&wire).unwrap().origin(), Some(origin));

// A function the standard doesn't define still has a frame, so a
// receiver can see what arrived before refusing it.
let frame = BvllFrame::decode(&[0x81, 0x0C, 0x00, 0x04]).unwrap();
assert_eq!(frame.function, BvlcFunction::from_raw(0x0C));
assert!(!frame.function.is_defined());
assert!(frame.message().is_err());

License

MIT