Skip to main content

rustbac_client/
lib.rs

1//! High-level async BACnet client.
2//!
3//! [`BacnetClient`] wraps any [`DataLink`](rustbac_datalink::DataLink)
4//! transport and exposes ergonomic methods for common BACnet operations
5//! such as reading properties, discovering devices, and subscribing to
6//! change-of-value (COV) notifications.
7
8/// Alarm and event services (GetAlarmSummary, GetEventInformation, etc.).
9pub mod alarm;
10/// Core [`BacnetClient`] type and transport setup.
11pub mod client;
12/// Change-of-value (COV) notification types.
13pub mod cov;
14/// Device and object discovery (Who-Is / I-Am / Who-Has).
15pub mod discovery;
16/// Client-level error type.
17pub mod error;
18/// Atomic file read/write operations.
19pub mod file;
20/// Long-running async notification listener.
21pub mod listener;
22/// Point type inference for BACnet objects.
23pub mod point;
24/// ReadRange results and related types.
25pub mod range;
26/// Schedule and Calendar convenience helpers.
27pub mod schedule;
28/// Lightweight simulated BACnet device.
29pub mod simulator;
30/// Owned application-data values for client-side use.
31pub mod value;
32/// Device discovery walk — reads all objects and their properties.
33pub mod walk;
34
35pub use alarm::{
36    AlarmSummaryItem, EnrollmentSummaryItem, EventInformationItem, EventInformationResult,
37    EventNotification,
38};
39pub use client::{BacnetClient, ForeignDeviceRenewal};
40pub use cov::{CovNotification, CovPropertyValue};
41pub use discovery::{DiscoveredDevice, DiscoveredObject};
42pub use error::ClientError;
43pub use file::{AtomicReadFileResult, AtomicWriteFileResult};
44pub use listener::{create_notification_listener, Notification, NotificationListener};
45pub use point::{PointClassification, PointDirection, PointKind};
46pub use range::{ClientBitString, ReadRangeResult};
47pub use rustbac_bacnet_sc::BacnetScTransport;
48pub use rustbac_core::services::acknowledge_alarm::{EventState, TimeStamp};
49pub use rustbac_core::services::device_management::{DeviceCommunicationState, ReinitializeState};
50pub use rustbac_datalink::bip::transport::{BroadcastDistributionEntry, ForeignDeviceTableEntry};
51pub use schedule::{CalendarEntry, DateRange, TimeValue};
52pub use simulator::SimulatedDevice;
53pub use value::ClientDataValue;
54pub use walk::{DeviceWalkResult, ObjectSummary};
55
56// Internal helpers used by simulator module.
57use rustbac_core::encoding::{primitives::decode_unsigned, reader::Reader, tag::Tag};
58use rustbac_core::types::ObjectId;
59
60fn decode_ctx_unsigned(r: &mut Reader<'_>) -> Result<u32, ClientError> {
61    match Tag::decode(r)? {
62        Tag::Context { len, .. } => Ok(decode_unsigned(r, len as usize)?),
63        _ => Err(ClientError::UnsupportedResponse),
64    }
65}
66
67fn decode_ctx_object_id(r: &mut Reader<'_>) -> Result<ObjectId, ClientError> {
68    Ok(ObjectId::from_raw(decode_ctx_unsigned(r)?))
69}
70
71fn data_value_to_client(value: rustbac_core::types::DataValue<'_>) -> ClientDataValue {
72    match value {
73        rustbac_core::types::DataValue::Null => ClientDataValue::Null,
74        rustbac_core::types::DataValue::Boolean(v) => ClientDataValue::Boolean(v),
75        rustbac_core::types::DataValue::Unsigned(v) => ClientDataValue::Unsigned(v),
76        rustbac_core::types::DataValue::Signed(v) => ClientDataValue::Signed(v),
77        rustbac_core::types::DataValue::Real(v) => ClientDataValue::Real(v),
78        rustbac_core::types::DataValue::Double(v) => ClientDataValue::Double(v),
79        rustbac_core::types::DataValue::OctetString(v) => ClientDataValue::OctetString(v.to_vec()),
80        rustbac_core::types::DataValue::CharacterString(v) => {
81            ClientDataValue::CharacterString(v.to_string())
82        }
83        rustbac_core::types::DataValue::BitString(v) => ClientDataValue::BitString {
84            unused_bits: v.unused_bits,
85            data: v.data.to_vec(),
86        },
87        rustbac_core::types::DataValue::Enumerated(v) => ClientDataValue::Enumerated(v),
88        rustbac_core::types::DataValue::Date(v) => ClientDataValue::Date(v),
89        rustbac_core::types::DataValue::Time(v) => ClientDataValue::Time(v),
90        rustbac_core::types::DataValue::ObjectId(v) => ClientDataValue::ObjectId(v),
91        rustbac_core::types::DataValue::Constructed { tag_num, values } => {
92            ClientDataValue::Constructed {
93                tag_num,
94                values: values.into_iter().map(data_value_to_client).collect(),
95            }
96        }
97    }
98}