Skip to main content

Crate bacnet_services

Crate bacnet_services 

Source
Expand description

§bacnet-services

BACnet service request and response parameter codecs for the Rusty BACnet workspace. Each module provides structures and byte encoders/decoders for a service family. Property values at constructed boundaries remain raw bytes for the application to interpret. This crate does not perform network requests or operate a device.

§Quickstart from development source

Use a checkout named rusty-bacnet beside your application directory. These blocks describe development-source dependencies, not the contents of a published release. The example imports bacnet-types directly, so it is listed too, and bytes is there for the BytesMut encoders mentioned after it. Adjust the paths for another layout.

[dependencies]
bacnet-services = { path = "../rusty-bacnet/crates/bacnet-services" }
bacnet-types = { path = "../rusty-bacnet/crates/bacnet-types" }
bytes = "1"

Encode and decode ReadProperty service parameters. These are only the service body: no confirmed-request APDU, NPDU, transport frame or device interaction is created by this example.

use bacnet_services::read_property::ReadPropertyRequest;
use bacnet_types::enums::{ObjectType, PropertyIdentifier};
use bacnet_types::primitives::ObjectIdentifier;

fn main() -> Result<(), bacnet_types::error::Error> {
    let request = ReadPropertyRequest {
        object_identifier: ObjectIdentifier::new_addressable(ObjectType::ANALOG_INPUT, 7)?,
        property_identifier: PropertyIdentifier::PRESENT_VALUE,
        property_array_index: None,
    };
    let mut storage = [0; 16];
    let mut tail = &mut storage[..];
    let written = request.encode_to_sink(&mut tail).expect("16 octets hold the request");
    let wire = &storage[..written];
    assert_eq!(wire, &[0x0C, 0, 0, 0, 7, 0x19, 85]);
    assert_eq!(ReadPropertyRequest::decode(wire)?, request);
    assert!(ReadPropertyRequest::decode(&wire[..1]).is_err());
    Ok(())
}

With alloc, request.encode(&mut wire) appends the same octets to a bytes::BytesMut.

§Without an allocator

Who-Is, I-Am and ReadProperty (request and ACK) encode into the caller’s storage and decode from borrowed octets with neither std nor alloc (#1614). ReadPropertyAckRef borrows the property value in place of the owned ACK’s Vec:

use bacnet_services::read_property::ReadPropertyAckRef;
use bacnet_services::who_is::{DeviceInstanceRange, WhoIsRequest};

fn main() -> Result<(), bacnet_types::error::Error> {
    let mut storage = [0; 16];
    let mut tail = &mut storage[..];
    let who_is = WhoIsRequest {
        range: Some(DeviceInstanceRange::new(1000, 2000)?),
    };
    let written = who_is.encode_to_sink(&mut tail).expect("16 octets hold a Who-Is");
    assert_eq!(storage[..written], [0x0A, 0x03, 0xE8, 0x1A, 0x07, 0xD0]);

    // [0] analog input 1, [1] Present_Value, [3] REAL 72.5.
    let ack = [0x0C, 0, 0, 0, 1, 0x19, 0x55, 0x3E, 0x44, 0x42, 0x91, 0, 0, 0x3F];
    let read = ReadPropertyAckRef::decode(&ack)?;
    assert_eq!(read.property_value, &[0x44, 0x42, 0x91, 0, 0]);
    Ok(())
}

§Features and allocation

The crate has three profiles. With neither std nor alloc it builds without an allocator, with the services above only.

ProfileFeaturesWhat it has
Hostedstd (default)Every service; enables alloc and standard-library support in bacnet-types, bacnet-encoding and bytes.
no_std with a heapallocEvery service; enables the foundation crates’ alloc profiles. Firmware must supply a global allocator.
No allocatorneitherwho_is and read_property: their encode_to_sink and decode, and ReadPropertyAckRef. The BytesMut encoders, the owned ReadPropertyACK and every other service need alloc.

For alloc-only dependencies, replace the entire dependency block, disabling defaults on every directly listed foundation crate and on bytes:

[dependencies]
bacnet-services = { path = "../rusty-bacnet/crates/bacnet-services", default-features = false, features = ["alloc"] }
bacnet-types = { path = "../rusty-bacnet/crates/bacnet-types", default-features = false, features = ["alloc"] }
bytes = { version = "1", default-features = false }

The same example executes on a host with either block. Firmware additionally supplies an allocator and a compatible bytes atomic backend. A target without atomic compare-and-swap, such as ARMv6-M, needs bytes’s extra-platforms feature and a firmware-selected portable-atomic backend. The block above does not choose that backend. For a build without an allocator, depend on bacnet-services and bacnet-types with default-features = false and no features, and leave out bytes, which that profile doesn’t use. CI builds each profile for ARMv6-M, ARMv7E-M and RISC-V (scripts/ci/check-no-std.sh) but doesn’t run it there. Cargo features are additive; another dependency can still enable alloc or std.

§API documentation

This README is also the crate’s Rust documentation landing page. The docs.rs profile explicitly enables std, disables implicit defaults, and renders only the default x86_64-unknown-linux-gnu target. It exposes the actual hosted API without bypassing feature gates or claiming firmware qualification.

Modules§

alarm_event
Alarm acknowledgment, event notification, and event information services.
alarm_summary
GetAlarmSummary service per ASHRAE 135-2020 Clause 13.10 (deprecated).
audit
Audit notification and query wire models.
common
Shared BACnet service data types per ASHRAE 135-2020 Clause 21.
cov
COV (Change of Value) services per ASHRAE 135-2020 Clauses 13.6, 13.7, 13.14 and 13.15.
cov_multiple
SubscribeCOVPropertyMultiple and COVNotificationMultiple services per ASHRAE 135-2020 Clauses 13.16–13.18.
device_mgmt
Device management services per ASHRAE 135-2020 Clause 16.
enrollment_summary
GetEnrollmentSummary service per ASHRAE 135-2020 Clause 13.11.
file
AtomicReadFile / AtomicWriteFile services per ASHRAE 135-2020 Clauses 14.1–14.2.
life_safety
LifeSafetyOperation service per ASHRAE 135-2020 Clause 13.13.
list_manipulation
AddListElement / RemoveListElement services per ASHRAE 135-2020 Clauses 15.1 and 15.2.
object_mgmt
Object management services per ASHRAE 135-2020 Clause 15.3-15.4.
private_transfer
ConfirmedPrivateTransfer / UnconfirmedPrivateTransfer services per ASHRAE 135-2020 Clauses 16.2 and 16.3.
read_property
ReadProperty service per ASHRAE 135-2020 Clause 15.5.
read_range
ReadRange service per ASHRAE 135-2020 Clause 15.8.
rpm
ReadPropertyMultiple service per ASHRAE 135-2020 Clause 15.7.
structured_error
The Clause 21 error productions that replace the plain class/code pair, read by the service the Error PDU answers:
text_message
ConfirmedTextMessage / UnconfirmedTextMessage services per ASHRAE 135-2020 Clauses 16.5 and 16.6.
virtual_terminal
Virtual Terminal (VT) services per ASHRAE 135-2020 Clauses 17.2–17.4.
who_am_i
Who-Am-I and You-Are services per ASHRAE 135-2020 Clause 16.11.
who_has
Who-Has and I-Have services per ASHRAE 135-2020 Clause 16.9.
who_is
Who-Is and I-Am services per ASHRAE 135-2020 Clause 16.10.
wpm
WritePropertyMultiple service per ASHRAE 135-2020 Clause 15.10.
write_group
WriteGroup service per ASHRAE 135-2020 Clause 15.11.
write_property
WriteProperty service per ASHRAE 135-2020 Clause 15.9.