pub struct BACnetServer<T: TransportPort = AnyTransport> { /* private fields */ }Expand description
BACnet server with APDU dispatch and service handling.
T is the transport the server runs over. It defaults to
AnyTransport, so BACnetServer alone names a server over any
built-in transport; BACnetServer<BipTransport> and the like name one
over a concrete transport.
Implementations§
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn generic_builder() -> ServerBuilder<T>
pub fn generic_builder() -> ServerBuilder<T>
Start a server builder for a caller-supplied transport type, with default configuration and stock Device generation unless a database is supplied.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn start(
config: ServerConfig,
db: ObjectDatabase,
transport: T,
) -> Result<Self, Error>
pub async fn start( config: ServerConfig, db: ObjectDatabase, transport: T, ) -> Result<Self, Error>
Start with the default system-UTC Device clock.
Sourcepub async fn start_with_clock(
config: ServerConfig,
db: ObjectDatabase,
transport: T,
clock_config: ClockConfig,
) -> Result<Self, Error>
pub async fn start_with_clock( config: ServerConfig, db: ObjectDatabase, transport: T, clock_config: ClockConfig, ) -> Result<Self, Error>
Start with a validated Device clock configuration.
Sourcepub async fn start_clockless(
config: ServerConfig,
db: ObjectDatabase,
transport: T,
) -> Result<Self, Error>
pub async fn start_clockless( config: ServerConfig, db: ObjectDatabase, transport: T, ) -> Result<Self, Error>
Start without a Device wall clock or time-synchronization execution.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn report_device_reset_local(&self) -> Result<(), Error>
pub async fn report_device_reset_local(&self) -> Result<(), Error>
Report a reset the application carries out for its own reasons, not at a peer’s ReinitializeDevice request: a DEVICE_RESET Audit record from this device, with no invoke ID (Clause 19.6, Table 19-5 covers resets for any reason, #1564).
An accepted WARMSTART or COLDSTART is recorded already; don’t report it again. The record goes through the Reporter that monitors the local Device, under that Device’s audit policy, as a peer’s reset’s does, and does nothing when no Reporter selects it. It returns once the record is admitted, not delivered, so call it before the restart begins and give delivery time before the process exits.
§Errors
The stopped-server error once stop has run.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn group_source_request_drops(&self) -> u64
pub fn group_source_request_drops(&self) -> u64
Confirmed requests ignored since start because the link-layer address
they came from is a group destination of the transport
(TransportPort::is_group_destination),
such as a B/IP broadcast or multicast address (#1504). The answer, and
the confirmed COV notifications of a subscription such a request
makes, would go back to that address, so the request is neither
executed nor answered. No built-in transport hands one up; a custom
one can.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn dcc_outcome_counters(&self) -> DccOutcomeCounters
pub fn dcc_outcome_counters(&self) -> DccOutcomeCounters
Sample completed admitted DCC outcomes, including after stop().
Excludes pre-handler rejections, duplicates, incomplete cancelled handlers,
timer expiry and response delivery outcomes. No history is retained.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn broadcast_i_am(&self) -> Result<(), Error>
pub async fn broadcast_i_am(&self) -> Result<(), Error>
Broadcast I-Am through this server’s bounded local-send owner.
Cancelling the waiter leaves admitted work owned until completion or stop.
While DeviceCommunicationControl restricts initiation nothing is sent
and this fails with SERVICES / COMMUNICATION_DISABLED (Clause 16.1).
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn purge_audit_log(&self, oid: &ObjectIdentifier) -> Result<(), Error>
pub async fn purge_audit_log(&self, oid: &ObjectIdentifier) -> Result<(), Error>
Purge an Audit Log: clear its records and append a BUFFER_PURGED
status record, as AuditLogObject::purge describes.
Peers have no way to do this, so it is the application’s to call. The log builds the purged state and queues its commit; the server waits for the commit with the object database guard dropped, so other requests carry on, and the log serves the purged state only once it is durable. Changes to one log land one at a time, in the order they were staged: a notification batch whose commit is running lands first and is purged with the rest, and one that arrives while the purge commits waits for it and follows the purge record.
§Errors
- OBJECT / UNKNOWN_OBJECT when
oidnames no object, and OBJECT / OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED when the object cannot be purged (it is not a built-in Audit Log). - DEVICE / OPERATIONAL_PROBLEM without a valid local clock, or when the commit fails; the log’s writer logs the storage error.
- The stopped-server error once
stophas run.
On any error the log is left as it was. A purge whose future is dropped before it finishes is handled as an abandoned write request is: the log keeps serving its state, drops the staged purge once it has waited long enough, and sets storage back to that state.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn event_notification_counters(&self) -> EventNotificationCounters
pub fn event_notification_counters(&self) -> EventNotificationCounters
Sample the lifetime totals of undelivered event notifications,
including after stop(). See EventNotificationCounters for what
each field counts and what is left out.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn local_mac(&self) -> &[u8] ⓘ
pub fn local_mac(&self) -> &[u8] ⓘ
Return the last bound local MAC snapshot, including after stop. This retained address does not assert that the transport is still active.
Sourcepub fn transport(&self) -> Option<&T>
pub fn transport(&self) -> Option<&T>
The transport the server’s network layer runs on, for its
transport-specific state: a B/IPv6 server’s local_address(), which
a peer turns into this server’s VMAC with resolve_virtual_address,
or a transport’s counters. None once the server no longer holds its
network layer.
Sourcepub fn database(&self) -> &Arc<RwLock<ObjectDatabase>> ⓘ
pub fn database(&self) -> &Arc<RwLock<ObjectDatabase>> ⓘ
Get a reference to the shared object database.
Objects read through this handle return raw standalone data. A built-in
Device follows its declared service profile, with absent or empty COV lists.
Served Device definitions and live lists belong to the executor: use
read_local for that view. Normal Device mutation and
replacement cannot change the served execution profile.
Install Device objects before startup: changing their membership through
this handle does not rebind the discovery limiter’s startup identity.
A clone the application keeps can outlive the server’s own handle, and
whichever goes last drops every object, waiting for the saves durable
objects have queued. In async code, let go of such a clone with
drop_database_off_runtime, so that wait runs on Tokio’s blocking
pool instead of a runtime worker (#1513).
Sourcepub async fn read_local(
&self,
oid: &ObjectIdentifier,
property: PropertyIdentifier,
array_index: Option<u32>,
) -> Result<PropertyValue, Error>
pub async fn read_local( &self, oid: &ObjectIdentifier, property: PropertyIdentifier, array_index: Option<u32>, ) -> Result<PropertyValue, Error>
Read one local property through the server’s ReadProperty evaluator.
Device wildcard reads target the configured identity; removal returns UNKNOWN_OBJECT even if another Device is present. The database’s lowest Device instance still owns the live COV lists, independent of insertion order; other Device objects receive empty lists. Every served Device uses the executor’s services, COV presence and property definitions, even after public profile mutation, replacement or custom object installation.
This is the live local read boundary: it applies the same Device
wildcard resolution, UNKNOWN_OBJECT and PROPERTY_IS_NOT_AN_ARRAY
checks, and value source as network ReadProperty. The selected Device’s
Active_COV_Subscriptions (ordinary and single-property subscriptions)
and Active_COV_Multiple_Subscriptions (SubscribeCOVPropertyMultiple
contexts) are projected from the COV subscription table at one sampled
instant, returned as their encoded BACnetLIST of BACnetCOVSubscription
and BACnetLIST of BACnetCOVMultipleSubscription
(PropertyValue::ApplicationData). After stop the
server services no subscriptions, so both properties read as empty lists.
The selected Device’s Device_Address_Binding lists the server’s device
bindings at the time of the read (#1369): each configured
DeviceBinding and each device whose I-Am was heard in the last ten
minutes, in Device instance order, as a PropertyValue::List whose
items are encoded BACnetAddressBindings
(PropertyValue::ApplicationData). A device on this network has
network number 0. The bindings outlast stop, so they still read then.
A Group’s Present_Value is rebuilt from its members, whose rows count
against the ReadPropertyMultiple work limit
(ReadPropertyMultipleBudget::max_result_elements)
as for network ReadProperty; past it the read fails with
Error::abort carrying OUT_OF_RESOURCES.
Sourcepub async fn write_local_encoded(
&self,
oid: &ObjectIdentifier,
property: PropertyIdentifier,
array_index: Option<u32>,
value: &[u8],
priority: Option<u8>,
source: LocalCommandSource,
) -> Result<(), Error>
pub async fn write_local_encoded( &self, oid: &ObjectIdentifier, property: PropertyIdentifier, array_index: Option<u32>, value: &[u8], priority: Option<u8>, source: LocalCommandSource, ) -> Result<(), Error>
Write one local property from its encoded value: the octets a network WriteProperty would carry for it.
The octets take the steps the WriteProperty handler takes before an
object sees a value. An array index is refused as it is over the
network (UNKNOWN_PROPERTY for a property the object doesn’t hold,
PROPERTY_IS_NOT_AN_ARRAY for one that isn’t an array), and the octets
are decoded with that handler’s per-property framing, which hands a
Schedule’s Effective_Period or a Staging’s Stages to the object in the
form it decodes. The value then takes the write_local
path, with its COV, event and audit work. A value read with
read_local and encoded therefore writes back, and
any value a network client could write is accepted here.
Like write_local, it must be awaited inside a Tokio runtime, failing
before anything is written outside one, and a caller dropped once the
write has committed skips none of the work the write owes (#1367).
Sourcepub fn i_am_broadcaster(&self) -> IAmBroadcaster<T>
pub fn i_am_broadcaster(&self) -> IAmBroadcaster<T>
Create a cloneable handle for unsolicited I-Am announcements.
Sourcepub fn comm_state(&self) -> DccState
pub fn comm_state(&self) -> DccState
Get the communication state per DeviceCommunicationControl.
The server refuses the deprecated DISABLE, so this is
DccState::Enable or DccState::DisableInitiation.
Sourcepub async fn generate_pics(&self, pics_config: &PicsConfig) -> Pics
pub async fn generate_pics(&self, pics_config: &PicsConfig) -> Pics
Generate PICS from the database and the server’s effective Device execution view.
Standalone PicsGenerator keeps raw-object semantics.
The caller must supply a PicsConfig for fields not available from the server
(device profile, data links, network roles, etc.). The vendor and model names, the firmware and
application versions, and the protocol version and revision come from the served Device object,
so the PICS can’t contradict what the device reports.
Source§impl<T: TransportPort + AsBip + 'static> BACnetServer<T>
impl<T: TransportPort + AsBip + 'static> BACnetServer<T>
Sourcepub fn foreign_registration(&self) -> Result<ForeignRegistrationSnapshot, Error>
pub fn foreign_registration(&self) -> Result<ForeignRegistrationSnapshot, Error>
How this server’s foreign-device registration is going (#938):
whether it holds a live lease, the time left on it, and the last
attempt’s result and outcome, a BBMD’s refusal included. It reads
BipTransport::bvlc_client_snapshot and sends nothing. Fails on a
transport that isn’t B/IP, and once the server has stopped.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Evaluate an authenticated local presentation and record a terminal result.
A grant or denial installs all its event intents in order; pending, unresolved and no-authorization results publish nothing, including their intermediate intents. The full request supplies every evaluation policy and operational fact. The caller owns retries, tag progression and replay handling: repeating a terminal attempt is a new publication, even when its tag is unchanged. Evaluation and event installation share one DB guard.
Each event names its associated credential (the companion for BY) and is stamped by the point. No physical factor is supplied, so the absent-factor UNDEFINED representation applies (Clauses 12.31.27–31). Equal/backward clocks advance the event trigger, and an exhausted timestamp representation refuses the entire batch. This route performs no physical door action.
Runtime, stopped-network, unknown/wrong object, unsupported batch, malformed admission and out-of-service/fault errors leave state unchanged. Contention retries release all guards before waiting and observe fresh state; progress is cooperative once contention quiesces, not a starvation/latency guarantee.
A committed attempt retains snapshots for ordered COV fanout through the existing notification lifecycle. Caller cancellation after commit does not discard owned work. DCC, budgets, send failures and shutdown still apply; success is not remote acknowledgment or durable delivery. Independent transactions have no global notification-order guarantee.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn report_access_event_local(
&self,
oid: &ObjectIdentifier,
report: AccessEventReport,
) -> Result<(), Error>
pub async fn report_access_event_local( &self, oid: &ObjectIdentifier, report: AccessEventReport, ) -> Result<(), Error>
Report an access event at an Access Point: Access_Event,
Access_Event_Tag, Access_Event_Time, Access_Event_Credential and
Access_Event_Authentication_Factor change together (Clause
12.31.27.1), checked as AccessPointObject::set_access_event checks
them (VALUE_OUT_OF_RANGE for a credential reference, factor or event
it refuses; an event is a named BACnetAccessEvent or a proprietary
one from 512 to 65535). A report without a time is stamped from the
Device clock.
Access_Event_Time is the point’s Table 13-1 trigger, so each event
with a new time sends the SubscribeCOV report, carrying all five
values. A time the point stamps itself is strictly after the one it
served, so several events of one transaction each move the time and
each report. While Out_Of_Service is TRUE (Clause 12.31.8), or
Reliability isn’t NO_FAULT_DETECTED (Clause 12.31.7), the point
performs no authentication, so an event is refused with PROPERTY /
WRITE_ACCESS_DENIED and nothing changes. An unknown object fails
with OBJECT / UNKNOWN_OBJECT and any object other than an Access
Point with OBJECT / OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED. The Python
binding exposes this as BACnetServer.report_access_event_local.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything is written outside one, and a
caller dropped once the event has committed skips none of the work
it owes (#1367).
Sourcepub async fn report_credential_read_local(
&self,
oid: &ObjectIdentifier,
report: CredentialReadReport,
) -> Result<(), Error>
pub async fn report_credential_read_local( &self, oid: &ObjectIdentifier, report: CredentialReadReport, ) -> Result<(), Error>
Report a factor a Credential Data Input’s reader has read: Present_Value and Update_Time change together (Clause 12.36.11). The factor must name one of the reader’s declared formats with its class, or be the UNDEFINED or ERROR factor with class 0, else VALUE_OUT_OF_RANGE. A report without a time is stamped from the Device clock, or the object’s next sequence number without a usable clock, so reading the same card again still moves Update_Time.
Update_Time is the reader’s Table 13-1 trigger, so each read with a
new time sends the SubscribeCOV report. While Out_Of_Service is TRUE
a client may be simulating the reader, so the read replaces the
reader’s values put aside, as set_present_value does (#1168): the
served values, and with them the COV report, stay as they are, and
the return to service serves the latest read. The other errors are
those of Self::report_access_event_local, for a Credential Data
Input. The Python binding exposes this as
BACnetServer.report_credential_read_local.
The Tokio-runtime rule of write_local applies.
Sourcepub async fn report_door_state_local(
&self,
oid: &ObjectIdentifier,
report: DoorStateReport,
) -> Result<(), Error>
pub async fn report_door_state_local( &self, oid: &ObjectIdentifier, report: DoorStateReport, ) -> Result<(), Error>
Report an Access Door’s hardware state: whichever of Door_Status, Lock_Status and Door_Alarm_State the report gives, together. Each must fall in its production, and the alarm state be NORMAL or a member of Alarm_Values or Fault_Values and no member of Masked_Alarm_Values, else VALUE_OUT_OF_RANGE and nothing changes.
Door_Alarm_State is the door’s Table 13-1 trigger, so a change of it
sends the SubscribeCOV report, and the event pass after the write
runs the door’s CHANGE_OF_STATE and FAULT_STATE algorithms on it at
once. Secured_Status follows the new values on its next read. While
Out_Of_Service is TRUE a client may be simulating the door, so the
report replaces the device values put aside, as the door’s setters do
(#1131): the served values stay, so no COV report or event follows,
and the return to service serves the latest values reported. The
other errors are those of
Self::report_access_event_local, for an Access Door. The Python
binding exposes this as BACnetServer.report_door_state_local.
The Tokio-runtime rule of write_local applies.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn set_life_safety_operation_expected_local(
&self,
oid: &ObjectIdentifier,
operation: LifeSafetyOperation,
) -> Result<(), Error>
pub async fn set_life_safety_operation_expected_local( &self, oid: &ObjectIdentifier, operation: LifeSafetyOperation, ) -> Result<(), Error>
Arm or rearm a Life Safety object from trusted local application logic.
This uses the object-internal state channel under the database write
lock. Network WriteProperty and WritePropertyMultiple remain unable to
forge Operation_Expected. After the lock is released, an actual
Operation_Expected readback change uses the exact Life Safety COV path;
rearming to the current value emits no notification.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything changes outside one. Once the
object holds the operation, the timestamped capture and the COV
fanout the change owes run as a task of their own in the server’s
request task set, which this future only waits for, so a caller
dropped then skips none of it (#1520). stop() aborts that task with
the other request tasks.
Sourcepub async fn write_local(
&self,
oid: &ObjectIdentifier,
property: PropertyIdentifier,
array_index: Option<u32>,
value: PropertyValue,
priority: Option<u8>,
source: LocalCommandSource,
) -> Result<(), Error>
pub async fn write_local( &self, oid: &ObjectIdentifier, property: PropertyIdentifier, array_index: Option<u32>, value: PropertyValue, priority: Option<u8>, source: LocalCommandSource, ) -> Result<(), Error>
Write a property on a local object and fire the same post-write COV
and event notifications that a network WriteProperty does. When target
Audit reporting is configured, the same observer records eligible local
writes with local Device provenance and no invoke ID; Device recipient
changes retain their sole old/new pair owner. Eligible actual AV/BV Audit
policy changes reserve immediate delivery before assignment; unavailable
resources return SERVICES/SERVICE_REQUEST_DENIED without a policy change.
This is the server-owned local-mutation entry point: it performs the
write under the database lock — routing OBJECT_NAME through the name
uniqueness check and index refresh, exactly like the network handler —
then releases the lock and runs the COV/event trigger path so a
subscription observes a local mutation just as it would a network one.
source explicitly selects the Device or an existing initiating object.
Tracked commands require a concrete selected Device; the selected Device
retains correction ownership regardless of the local initiator. Unrelated
properties preserve their behavior without a usable command origin.
Low-level object setters deliberately bypass this notification owner.
A NULL to a property that isn’t commandable and has no NULL in its datatype succeeds and changes nothing, as over the network (#1396): Audit records it, and no COV, event or Schedule work follows it.
An array index is checked first, as the WriteProperty handler checks it (#1426): UNKNOWN_PROPERTY for a property the object doesn’t hold, PROPERTY_IS_NOT_AN_ARRAY for one that isn’t an array. Neither the object nor Audit sees such a write. The writes a Command or Channel run makes here get the same check.
§Cancellation
Dropped before the write commits, the future makes no change. Once it
has committed, the work the write owes (the event pass, the COV
fanout, a re-evaluated Schedule’s target fanout, a Staging plan, and
the Command or Channel runs it started) runs as a task of its own in
the server’s request task set, which this future only waits for, so
dropping the future skips none of it (#1367): subscribers hear of the
change, and a run ends as it would have, reported to its property
subscribers. stop() aborts that task with the other request tasks,
as it does a request handler: what it hadn’t sent by then is not
sent, and a run it hadn’t started ends as if none of its writes were
made (#1324), In_Process FALSE with each command unsuccessful, or
Write_Status FAILED. The call still returns Ok(()) then: the write
was made. A panic in that work is raised again in the caller, as it
would be were the work done in place.
The future must be awaited inside a Tokio runtime, which the task is
spawned onto: outside one it fails with Error::Encoding before
anything is written.
Sourcepub async fn set_present_value_local(
&self,
oid: &ObjectIdentifier,
value: PropertyValue,
) -> Result<(), Error>
pub async fn set_present_value_local( &self, oid: &ObjectIdentifier, value: PropertyValue, ) -> Result<(), Error>
Supply a supported object’s logical Present_Value from Rust application code.
Analog, Binary and Multi-state Inputs, noncommandable Values, Loop (the control algorithm’s output) and Life Safety Point and Zone opt in. Binary Input values are logical INACTIVE/ACTIVE states after Polarity, not raw physical states. The update runs the existing post-write intrinsic-event and COV processing after the database lock is released; configured delays and distribution policy still control delivery, and a COV_Increment still filters Present_Value reports.
Applications are denied while Out_Of_Service is TRUE to protect a
client’s simulation value. This is local policy for Inputs and required
by the object clauses for the supported Values and Loop. NULL is an
invalid application value. Other object families fail closed; use
BACnetServer::write_local for network-equivalent writes and sourced
commands on commandable objects. The Python binding exposes this as
BACnetServer.set_present_value_local. A noncommandable Value that
tracks its source (set_value_source_tracking, #1552) then publishes
this server’s Device as Value_Source, as Clause 19.5 asks of a write
the local device makes.
A Life Safety Point or Zone takes an Enumerated BACnetLifeSafetyState,
a standard value or one from 256 to 65535, in or out of service, since
clients never write its Present_Value. The update leaves
Tracking_Value, Silenced and Operation_Expected alone, so any latching
until reset is the application’s (see
BACnetServer::set_tracking_value_local). A change notifies
SubscribeCOV and Present_Value property subscribers through the Life
Safety COV path. The built-in objects run no intrinsic reporting, so
the post-write event pass raises nothing for them.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything is written outside one, and a
caller dropped once the write has committed skips none of the work
the write owes (#1367).
Sourcepub async fn set_controlled_variable_value_local(
&self,
oid: &ObjectIdentifier,
value: PropertyValue,
) -> Result<(), Error>
pub async fn set_controlled_variable_value_local( &self, oid: &ObjectIdentifier, value: PropertyValue, ) -> Result<(), Error>
Supply a Loop’s measured Controlled_Variable_Value from the
application that runs its control algorithm.
The value is a finite REAL: another datatype fails with PROPERTY /
INVALID_DATA_TYPE and NaN or an infinity with PROPERTY /
VALUE_OUT_OF_RANGE. An unknown object fails with OBJECT /
UNKNOWN_OBJECT and any object other than a Loop with OBJECT /
OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED, the same errors as
BACnetServer::set_present_value_local. Unlike Present_Value it is
accepted while Out_Of_Service is TRUE, because Out_Of_Service
decouples only the output and Reliability from the algorithm.
The update runs the same post-write COV processing as
set_present_value_local once the database lock is released. A
SubscribeCOVProperty on Controlled_Variable_Value is notified of the
change; a SubscribeCOV on the Loop is not, since the Loop’s COV report
carries this value without being triggered by it, so its next report
carries the new value. The property stays read-only over the network.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything is written outside one, and a
caller dropped once the write has committed skips none of the work
the write owes (#1367).
Sourcepub async fn add_averaging_sample_local(
&self,
oid: &ObjectIdentifier,
sample: Option<PropertyValue>,
) -> Result<(), Error>
pub async fn add_averaging_sample_local( &self, oid: &ObjectIdentifier, sample: Option<PropertyValue>, ) -> Result<(), Error>
Record one sample for an Averaging object, taken by the application.
The server samples an object that holds an Object_Property_Reference
itself, every Window_Interval / Window_Samples seconds (#1144). For an
object without one, the application samples whatever it averages,
spacing its readings that far apart, and passes each result here. On an
object the server samples, a call is one more attempt in the window
and doesn’t move the server’s schedule. A value may be
a BOOLEAN (FALSE and TRUE count as 0 and 1), Signed, Unsigned,
Enumerated or finite REAL; the object keeps its statistics in REAL
(Clause 12.5). None records an attempt that produced no value, such
as a failed read: it counts toward Attempted_Samples but not
Valid_Samples. Another datatype, Double included, fails with PROPERTY /
INVALID_DATA_TYPE and NaN or an infinity with PROPERTY /
VALUE_OUT_OF_RANGE, and a refused sample counts as neither attempted
nor valid. An unknown object fails with OBJECT / UNKNOWN_OBJECT and any
object other than an Averaging object with OBJECT /
OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED, as with
BACnetServer::set_present_value_local.
Each call fills the next slot of the object’s window, dropping the
oldest once Window_Samples are held, and Minimum_Value, Maximum_Value,
Average_Value, Attempted_Samples and Valid_Samples change together
under the database lock; the server’s COV processing runs once the
lock is released. Averaging has no Table 13-1 row, so SubscribeCOV on
it is refused, but SubscribeCOVProperty and
SubscribeCOVPropertyMultiple are admitted: a numeric property is
reported when it moves by the subscription’s COV increment, or on any
change when the subscription gives none (Table 13-1a). A move to or
from the NaN or infinite value of an empty window is always reported,
and staying at it never is. The report has no Status_Flags because the
object has none. The Python binding exposes this as
BACnetServer.add_averaging_sample_local.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything is written outside one, and a
caller dropped once the write has committed skips none of the work
the write owes (#1367).
Sourcepub async fn set_tracking_value_local(
&self,
oid: &ObjectIdentifier,
value: PropertyValue,
) -> Result<(), Error>
pub async fn set_tracking_value_local( &self, oid: &ObjectIdentifier, value: PropertyValue, ) -> Result<(), Error>
Supply a Life Safety Point’s or Zone’s Tracking_Value, the live state
the application derived, while the server holds the object.
The value is an Enumerated naming a standard BACnetLifeSafetyState or
one from the proprietary range 256..=65535. A reserved or larger number
fails with PROPERTY / VALUE_OUT_OF_RANGE and another datatype with
PROPERTY / INVALID_DATA_TYPE. An unknown object fails with OBJECT /
UNKNOWN_OBJECT and any object other than a Life Safety Point or Zone
with OBJECT / OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED, as with
BACnetServer::set_present_value_local. Present_Value, Silenced and
Operation_Expected are left as they are: the object derives nothing
from Tracking_Value.
While Out_Of_Service is TRUE the value replaces the one set aside for
the return to service, and a client’s simulated Tracking_Value keeps
being served (#1108); the return to service then serves the latest
application value and notifies its subscribers. In service, a change
reaches SubscribeCOVProperty and SubscribeCOVPropertyMultiple
subscribers of Tracking_Value through the Life Safety COV path once the
database lock is released; whole-object SubscribeCOV reports don’t
carry it. The property stays read-only over the network in service.
The Python binding exposes this as BACnetServer.set_tracking_value_local.
Like write_local, it must be awaited inside a
Tokio runtime, failing before anything is written outside one, and a
caller dropped once the write has committed skips none of the work
the write owes (#1367).
Source§impl BACnetServer<ScTransport<TlsWebSocket>>
impl BACnetServer<ScTransport<TlsWebSocket>>
Sourcepub fn sc_builder() -> ScServerBuilder
Available on crate feature sc-tls only.
pub fn sc_builder() -> ScServerBuilder
sc-tls only.Create an SC-specific builder that connects to a BACnet/SC hub.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn request_admission_counters(&self) -> RequestAdmissionCounters
pub fn request_admission_counters(&self) -> RequestAdmissionCounters
Sample admission counters. Available after stop; active counts then are zero.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub async fn stop(&mut self) -> Result<(), Error>
pub async fn stop(&mut self) -> Result<(), Error>
Seal egress, join admitted work, and stop the owned transport.
Call it before dropping the server. A server dropped without it in
async code aborts its tasks and lets the object database go on Tokio’s
blocking pool once they have let go of it (#1409), so the drop returns
at once, but nothing waits for the objects’ last saves. Storage may
still change after such a drop returns, as those saves and the
put-back of a staged write (#1363) land, so stop().await before
building another server on the same storage.
Once its requests are joined, a write a Notification Forwarder,
Notification Class, Access Rights object or Audit Log still holds
staged for one of them is dropped, and stop waits until every save
those objects have queued has run, so storage holds the state each
object serves (#1363); see
DurableWrites::settle_forgotten_writes. A Trend Log, Trend Log
Multiple or Event Log kept in storage commits once more there, if it
changed since its last commit, and stop waits for that commit too
(#1541). That wait has no limit:
storage that stalls holds stop up, and a warning naming the objects
still saving is logged after 5 s and every 30 s after that. Stop does
not wait while the application holds the database: the objects then
settle from a task once it lets go, and put storage back when they
are dropped. That task lets go of its handle through
drop_database_off_runtime, so if it holds the last one the
objects drop on Tokio’s blocking pool.
A request’s abort lands when its task next yields, so a request already running when stop begins may find its save done and make its write first. Its answer is sealed, but the object serves that write, and storage holds it (#1457).
Cancelling this waiter leaves cleanup owned by the server. A later stop joins it; after transport cleanup begins, dropping the server lets that cleanup finish. Local mutation and broadcasts are rejected from the first stop poll; local reads and database inspection remain available.
Source§impl BACnetServer<BipTransport>
impl BACnetServer<BipTransport>
Sourcepub fn bip_builder() -> BipServerBuilder
pub fn bip_builder() -> BipServerBuilder
Create a BIP-specific builder with interface/port/broadcast fields.
Source§impl<T: TransportPort + 'static> BACnetServer<T>
impl<T: TransportPort + 'static> BACnetServer<T>
Sourcepub fn discovery_counters(&self) -> DiscoveryCounters
pub fn discovery_counters(&self) -> DiscoveryCounters
Get a snapshot of discovery rate-limiting counters.
Sourcepub fn cov_counters(&self) -> CovCounters
pub fn cov_counters(&self) -> CovCounters
Get a snapshot of COV operational and telemetry counters.
Sourcepub fn mutation_decision_counters(&self) -> MutationDecisionCounters
pub fn mutation_decision_counters(&self) -> MutationDecisionCounters
Sample lifetime mutation authorization decisions, including after stop().
Counts decisions, not completed handlers or response delivery; see
MutationDecisionCounters.
Sourcepub async fn remove_peer_subscriptions(
&self,
mac: &[u8],
network: Option<&NpduAddress>,
) -> usize
pub async fn remove_peer_subscriptions( &self, mac: &[u8], network: Option<&NpduAddress>, ) -> usize
Remove COV subscriptions using this current immediate MAC and routed source. Cleanup of an obsolete router leaves subscriptions renewed onto another route. Only removed entries release their contribution to the shared quota group.
Trait Implementations§
Source§impl<T: TransportPort> Drop for BACnetServer<T>
impl<T: TransportPort> Drop for BACnetServer<T>
Source§fn drop(&mut self)
fn drop(&mut self)
Seal the server and abort its tasks. In async code the object
database then drops on Tokio’s blocking pool (#1409): the drop returns
before the objects’ last saves land, so storage may still change after
it. Call stop first to wait for them. A clone
of database the application still holds
keeps the objects alive; let go of it with
drop_database_off_runtime (#1513).