pub struct ObjectDatabase { /* private fields */ }Expand description
A collection of BACnet objects, keyed by ObjectIdentifier.
Enforces Object_Name uniqueness within a device. Maintains secondary indexes for O(1) name lookup and O(1) type lookup.
Implementations§
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn sample_due_averaging_objects(
&mut self,
now: Duration,
) -> Vec<ObjectIdentifier>
pub fn sample_due_averaging_objects( &mut self, now: Duration, ) -> Vec<ObjectIdentifier>
Take every Averaging sample due at the monotonic instant now and
return the objects that recorded one, for COV processing.
The caller must hold exclusive database access for the whole call. A
due object names the local property it averages
(take_due_averaging_sample_internal); this reads it and records the
value. An attempt that yields nothing usable is recorded as a miss,
which counts toward Attempted_Samples but not Valid_Samples: a
referenced object or property that doesn’t exist, an array index on a
property that isn’t an array, any other read error, and a value the
object refuses to average (a datatype outside the five Clause 12.5
accepts, or a REAL that isn’t finite).
Without a bound monotonic clock nothing is ever due. Reads go through
BACnetObject::read_property,
so they must stay bounded, as for Trend Log polling.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn follow_event_algorithm_inhibit(&mut self, oid: &ObjectIdentifier) -> bool
pub fn follow_event_algorithm_inhibit(&mut self, oid: &ObjectIdentifier) -> bool
Read the property the object oid’s Event_Algorithm_Inhibit_Ref
names and hand the value over as its Event_Algorithm_Inhibit; returns
whether that changed. An object with no reference, one that doesn’t
report intrinsically, or one this database doesn’t hold is left
alone.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn log_event_notification(
&mut self,
notification: &EventNotificationRequest,
)
pub fn log_event_notification( &mut self, notification: &EventNotificationRequest, )
Record an event notification this device generated in each of its Event Log objects, as a notification record stamped with the Device clock’s local date and time.
The server calls this for each notification it builds once the
recipient lookup has read the Notification Class. Each log’s own
lifecycle decides what it keeps, as for a record the application adds
through add_record: a disabled log ignores it, and a full log drops
its oldest record or, with Stop_When_Full, stops and records that
instead.
Two kinds go in no log, so that a report can’t prompt the next without
end, through the log it watches or crosswise through another log
watched in turn. One is a BUFFER_READY report on an Event Log’s buffer
(see reports_an_event_log_buffer), as for received notifications. The
other is any report from an Event Enrollment of this device monitoring
a property of an Event Log here: whatever its algorithm, it watches
something each record changes, such as Total_Record_Count, so it isn’t
only BUFFER_READY that would answer its own record. A Trend Log’s or
Trend Log Multiple’s report is logged like any other notification:
those logs take no notifications, so it can’t count toward the next.
Without a valid Device clock no record can carry its timestamp, so nothing is logged. A log that refuses the record keeps its state; the refusal goes to the trace log and the other logs still take it. The notification is stored as given, Process Identifier included: Clause 12.27 leaves that parameter of a locally generated record to the device.
Sourcepub fn collects_received_event_notifications(&self) -> bool
pub fn collects_received_event_notifications(&self) -> bool
Whether any Event Log has opted in to the notifications the device receives. The server asks before it decodes one.
Sourcepub fn takes_received_event_notification(
&self,
notification: &EventNotificationRequest,
) -> bool
pub fn takes_received_event_notification( &self, notification: &EventNotificationRequest, ) -> bool
Whether log_received_event_notification
would record notification, received from another device, anywhere:
some Event Log has opted in, and the notification is one a log may
take. The server asks before it spends any of a source’s allowance.
Sourcepub fn log_received_event_notification(
&mut self,
notification: &EventNotificationRequest,
)
pub fn log_received_event_notification( &mut self, notification: &EventNotificationRequest, )
Record an event notification this device received, as it decoded, in
each Event Log that has opted in with
EventLogObject::set_log_received_notifications,
stamped with the Device clock’s local date and time. Each log’s
lifecycle decides what it keeps, as for the device’s own
notifications, and each record counts toward the log’s
Notification_Threshold.
Two kinds are kept out. A BUFFER_READY report on an Event Log’s buffer
in any device isn’t logged (see reports_an_event_log_buffer), whatever
object reports it: another vendor’s Event Enrollment running the
algorithm on its Event Log names the log only there. Logging it could
prompt a report here that, logged there in turn, prompts the next. Any
other notification about an Event Log is logged. And one whose
Initiating Device Identifier names this device isn’t logged a second
time: the device logged it when it built it.
This records whatever it is given. The server calls it only for a notification that decoded in full, after holding each source to a few records a second, so a flood of them can’t push the device’s own records out of a log faster than that bound.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn check_input_reference(&mut self, oid: &ObjectIdentifier) -> bool
pub fn check_input_reference(&mut self, oid: &ObjectIdentifier) -> bool
Judge the Input_Reference of the Pulse Converter oid against this
database and hand it the verdict; returns whether its Reliability
changed, so the caller owes COV for it. Any other object, or one this
database doesn’t hold, is left alone.
The bundled server calls this as a write of Input_Reference commits, over WriteProperty, WritePropertyMultiple or the local write path; adding and removing objects calls it for the converters concerned.
Sourcepub fn count_pulse_inputs(&mut self) -> Vec<ObjectIdentifier>
pub fn count_pulse_inputs(&mut self) -> Vec<ObjectIdentifier>
Judge each Pulse Converter’s Input_Reference again and hand over a
reading of the property it names, so the converter counts its
increase into Count (Clause 12.23.14); returns the converters whose
Reliability or Count changed, for COV. A converter with nothing to
read gets None, which drops its baseline.
The bundled server runs this on every wake of its monotonic operation
task, so at least once a second. Reads go through
BACnetObject::read_property, so they must stay bounded, as for
Averaging sampling.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn selected_device(&self) -> Option<ObjectIdentifier>
pub fn selected_device(&self) -> Option<ObjectIdentifier>
The Device object this database represents, for wildcard reads, discovery, notifications and reference resolution.
Clause 12.11 expects one Device per BACnet device. When a database
holds several, the lowest instance wins: a deterministic local policy,
independent of hash or insertion order. A concrete instance always
precedes the wildcard instance, which is the highest; a database whose
only Device is the wildcard selects it. No Device yields None.
Sourcepub fn local_device(&self) -> LocalDevice
pub fn local_device(&self) -> LocalDevice
The Device a reference must name to stay inside this device: the selected Device when its instance is concrete.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn poll_trend_logs(&mut self) -> Duration
pub fn poll_trend_logs(&mut self) -> Duration
Poll every due local Trend Log or Trend Log Multiple synchronously and return the next wait.
Each acquisition reads every reference of the log: a Trend Log’s one,
or each Log_DeviceObjectProperty element of a Trend Log Multiple, whose
record then carries one value per element in array order (#1203).
Only this database is read. A reference whose Device member names
another device (see ObjectDatabase::local_device) is never read
here, even when a same-numbered local object exists: its value is a
failure, PROPERTY / OPTIONAL_FUNCTIONALITY_NOT_SUPPORTED. A Trend Log
Multiple element naming instance 4194303 is empty and fails with
PROPERTY / NO_PROPERTY_SPECIFIED. A reference with an array index reads
that element (#1205). A local read that fails yields the error a
ReadProperty of it would report: OBJECT / UNKNOWN_OBJECT for a missing
object, PROPERTY / PROPERTY_IS_NOT_AN_ARRAY for an index on a property
that isn’t an array, or the read’s own error, such as INVALID_ARRAY_INDEX
for an index past the end (#1183).
Only POLLED logs with a nonzero Log_Interval and at least one reference
are polled. A TRIGGERED log whose Trigger reads TRUE makes one
acquisition, and the object clears Trigger once it accepts the record
(Clauses 12.25.29 and 12.30.16). A Trend Log Multiple without members
records no values for it, and a Trend Log without a reference records
PROPERTY / NO_PROPERTY_SPECIFIED, so Trigger never stays TRUE. With
Align_Intervals TRUE and a Log_Interval that divides a day, a POLLED
log acquires when the Device clock’s time of day is Interval_Offset
(modulo the interval) past a multiple of the interval (Clauses
12.25.27-28 and 12.30.14-15); the first acquisition waits for such a
boundary. Such a log is judged against the Device clock on every pass,
so a clock change moves its plan with it (see the alignment module).
Every pass also lets each Trend Log, Trend Log Multiple and Event Log look at its Start_Time / Stop_Time window, with or without a monotonic clock, so one that opens or closes is recorded within a pass even when no record arrives. An Event Log takes its records from the application and the device’s notifications, never from this poller, but this pass is the one regular visit every log gets.
The caller must hold exclusive database access for this whole call. The bound monotonic clock drives scheduling; the shared Device clock provides each actual acquisition timestamp. Without either clock an attempt cannot succeed. A successful call to an object’s insertion hook, including its accepted disabled/count-only outcomes, starts the configured interval.
Log_Interval is in hundredths. Deadlines follow actual completion, without catch-up bursts. Invalid timestamps and insertion errors preserve the last success and retry after 100 ms. The returned wait is at most 100 ms so a timer-driven caller also reconciles configuration changes and idle logs. Slow synchronous work can make another object due; a minimum 1 ms yield avoids a zero-delay loop. These bounds are local policy, not real-time guarantees. Clock, object reads and insertion hooks must remain bounded.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn add(&mut self, object: Box<dyn BACnetObject>) -> Result<(), Error>
pub fn add(&mut self, object: Box<dyn BACnetObject>) -> Result<(), Error>
Add an object to the database.
Returns PROPERTY / DUPLICATE_NAME if another object already has the
same object_name(), as
check_name_available does.
Replacing an object with the same OID is allowed unless an installed
Audit runtime protects its membership. Protection is checked before any binding.
Once the object is in, every Pulse Converter whose Input_Reference
names it, or the object itself when it is one, has the reference
judged again (ObjectDatabase::check_input_reference); one whose
Reliability changes is queued for the server’s COV fanout. A Schedule
holding a refused reference to it is queued for the server to retry
that reference (#1440).
Sourcepub fn find_by_name(&self, name: &str) -> Option<&dyn BACnetObject>
pub fn find_by_name(&self, name: &str) -> Option<&dyn BACnetObject>
Look up an object by its name. O(1) via the name index.
Sourcepub fn check_name_available(
&self,
oid: &ObjectIdentifier,
new_name: &str,
) -> Result<(), Error>
pub fn check_name_available( &self, oid: &ObjectIdentifier, new_name: &str, ) -> Result<(), Error>
Check whether new_name is available for object oid.
Returns Ok(()) if the name is unused or already belongs to oid,
and PROPERTY / DUPLICATE_NAME if another object owns it. Clause 18.3
lists that code under the PROPERTY class, and the WriteProperty and
WritePropertyMultiple error tables (15.9.1.3.1, 15.10.1.3.1) give the
same pair; CreateObject’s table (15.3.1.3.1) has no row for a name in
use, so its initial values answer as WriteProperty does.
Sourcepub fn update_name_index(&mut self, oid: &ObjectIdentifier)
pub fn update_name_index(&mut self, oid: &ObjectIdentifier)
Update the name index after a successful Object_Name write.
Call this after write_property(OBJECT_NAME, …) succeeds.
Sourcepub fn get(&self, oid: &ObjectIdentifier) -> Option<&dyn BACnetObject>
pub fn get(&self, oid: &ObjectIdentifier) -> Option<&dyn BACnetObject>
Get a shared reference to an object by identifier.
Sourcepub fn get_mut(
&mut self,
oid: &ObjectIdentifier,
) -> Option<&mut (dyn BACnetObject + '_)>
pub fn get_mut( &mut self, oid: &ObjectIdentifier, ) -> Option<&mut (dyn BACnetObject + '_)>
Get a mutable reference to an object by identifier.
Sourcepub fn with_object_adapter<R, F>(
&mut self,
oid: &ObjectIdentifier,
adapt: F,
) -> Result<Option<R>, Error>
pub fn with_object_adapter<R, F>( &mut self, oid: &ObjectIdentifier, adapt: F, ) -> Result<Option<R>, Error>
Install an identity-preserving adapter through scoped structural access.
The callback must preserve the object’s identifier, name and type. It is responsible for allocating/validating before changing the slot. This hook neither rebinds clocks nor updates indexes, and does not provide rollback. Poll ownership is retired before invocation, even if the callback returns an error or unwinds after modifying the slot. Slot borrows cannot escape. An installed Audit runtime can reject protected members before the callback.
use bacnet_objects::{database::ObjectDatabase, traits::BACnetObject};
use bacnet_types::primitives::ObjectIdentifier;
fn escape<'a>(db: &'a mut ObjectDatabase, oid: &ObjectIdentifier)
-> Result<Option<&'a mut Box<dyn BACnetObject>>, bacnet_types::error::Error> {
db.with_object_adapter(oid, |slot| slot)
}Sourcepub fn enrollment_eval_state_invalidated(&self, oid: &ObjectIdentifier) -> bool
pub fn enrollment_eval_state_invalidated(&self, oid: &ObjectIdentifier) -> bool
Whether an Event Enrollment object’s private evaluator state requires a successful reset before reuse.
Sourcepub fn set_enrollment_eval_state_invalidated(
&mut self,
oid: ObjectIdentifier,
invalidated: bool,
)
pub fn set_enrollment_eval_state_invalidated( &mut self, oid: ObjectIdentifier, invalidated: bool, )
Mark or clear the reset requirement for Event Enrollment private state.
Sourcepub fn enrollment_eval_source(
&self,
oid: &ObjectIdentifier,
) -> Option<EventEnrollmentMonitoredSource>
pub fn enrollment_eval_source( &self, oid: &ObjectIdentifier, ) -> Option<EventEnrollmentMonitoredSource>
Return database-owned monitored-source state for a custom Event Enrollment object.
Sourcepub fn set_enrollment_eval_source(
&mut self,
oid: ObjectIdentifier,
source: Option<EventEnrollmentMonitoredSource>,
)
pub fn set_enrollment_eval_source( &mut self, oid: ObjectIdentifier, source: Option<EventEnrollmentMonitoredSource>, )
Store database-owned monitored-source state for a custom Event Enrollment object.
Sourcepub fn remove(
&mut self,
oid: &ObjectIdentifier,
) -> Result<Option<Box<dyn BACnetObject>>, Error>
pub fn remove( &mut self, oid: &ObjectIdentifier, ) -> Result<Option<Box<dyn BACnetObject>>, Error>
Remove an object by identifier. Installed Audit membership protection
returns an error before removing the object or changing indexes.
Pulse Converters whose Input_Reference names a removed object have
the reference judged again, as add does.
Sourcepub fn list_objects(&self) -> Vec<ObjectIdentifier>
pub fn list_objects(&self) -> Vec<ObjectIdentifier>
List all object identifiers in the database.
Sourcepub fn find_by_type(&self, object_type: ObjectType) -> Vec<ObjectIdentifier>
pub fn find_by_type(&self, object_type: ObjectType) -> Vec<ObjectIdentifier>
Find all objects of a given type.
Returns a Vec of ObjectIdentifiers whose object type matches object_type.
Useful for WhoHas, object enumeration, and similar queries.
Sourcepub fn iter_objects(
&self,
) -> impl Iterator<Item = (ObjectIdentifier, &dyn BACnetObject)>
pub fn iter_objects( &self, ) -> impl Iterator<Item = (ObjectIdentifier, &dyn BACnetObject)>
Iterate over all (ObjectIdentifier, &dyn BACnetObject) pairs.
Avoids the double-lookup pattern of list_objects() followed by get().
Sourcepub fn set_clock_reader(&mut self, clock: Option<Arc<dyn ClockReader>>)
pub fn set_clock_reader(&mut self, clock: Option<Arc<dyn ClockReader>>)
Bind one clock reader to the database and every object it contains.
Devices added after this call receive the same reader in add.
Sourcepub fn clock_frame(&self) -> Option<ClockFrame>
pub fn clock_frame(&self) -> Option<ClockFrame>
Read one coherent sample from the database’s shared clock.
Sourcepub fn for_each_object_mut<F>(&mut self, f: F)
pub fn for_each_object_mut<F>(&mut self, f: F)
Visit every (ObjectIdentifier, &mut dyn BACnetObject) pair.
Mutable counterpart to iter_objects, used by
the intrinsic-reporting tick task to advance pending transitions. A
callback is used (rather than a returned impl Iterator) so the
&mut dyn BACnetObject borrow is tied to this call’s lifetime.
Source§impl ObjectDatabase
impl ObjectDatabase
Sourcepub fn lighting_color(
&self,
lighting_output: &ObjectIdentifier,
) -> Option<LightingColor>
pub fn lighting_color( &self, lighting_output: &ObjectIdentifier, ) -> Option<LightingColor>
The colour the lighting output lighting_output shows now (#1527):
the Tracking_Value of the colour object its Color_Reference names, or
its Override_Color_Reference while Color_Override is TRUE, so a
colour fade in progress shows as it runs.
None when the object has no Color_Reference, the reference in use
names no object (instance 4194303), or this database holds no Color
or Color Temperature object by that identifier. It reads the
properties, so it follows any object that serves them.