1use std::collections::HashMap;
8use std::net::Ipv4Addr;
9use std::sync::Arc;
10#[cfg(test)]
11pub(crate) use std::sync::atomic::AtomicBool;
12use std::sync::atomic::Ordering;
13use std::time::Instant;
14
15use bytes::{Bytes, BytesMut};
16use tokio::sync::{Mutex, RwLock, Semaphore, mpsc, oneshot, watch};
17use tokio::task::JoinHandle;
18use tokio::time::Duration;
19use tracing::{debug, warn};
20
21use event_delivery::EventDelivery;
22
23use bacnet_encoding::apdu::{
24 self, AbortPdu, Apdu, ComplexAck, ConfirmedRequest as ConfirmedRequestPdu, ErrorPdu, RejectPdu,
25 SegmentAck as SegmentAckPdu, SimpleAck, UnconfirmedRequest as UnconfirmedRequestPdu,
26 encode_apdu,
27};
28use bacnet_encoding::npdu::NpduAddress;
29use bacnet_encoding::primitives::encode_property_value;
30use bacnet_encoding::segmentation::{
31 SegmentReceiver, SegmentedPduType, duplicate_in_window, max_segment_payload, split_payload,
32};
33use bacnet_network::layer::NetworkLayer;
34use bacnet_npdu::NetworkPriority;
35use bacnet_objects::database::ObjectDatabase;
36use bacnet_objects::notification_class::{
37 lookup_notification_recipients, resolve_transition_priority_ack,
38};
39use bacnet_services::alarm_event::EventNotificationRequest;
40use bacnet_services::common::BACnetPropertyValue;
41use bacnet_services::cov::COVNotificationRequest;
42use bacnet_services::cov_multiple::COVNotificationMultipleRequest;
43use bacnet_services::who_is::{DeviceInstanceRange, IAmRequest, WhoIsRequest};
44use bacnet_transport::any::AnyTransport;
45use bacnet_transport::bip::{BipMode, BipMulticast, BipTransport};
46use bacnet_transport::port::TransportPort;
47use bacnet_transport::warn_throttle::WarnThrottle;
48use bacnet_transport::warn_throttled;
49use bacnet_types::MacAddr;
50use bacnet_types::enums::{
51 AbortReason, ConfirmedServiceChoice, ErrorClass, ErrorCode, LifeSafetyOperation, NotifyType,
52 ObjectType, PropertyIdentifier, RejectReason, Segmentation, UnconfirmedServiceChoice,
53};
54use bacnet_types::error::{Error, RemoteError};
55use bacnet_types::primitives::{ObjectIdentifier, PropertyValue};
56
57use crate::audit_notification::{
58 AuditNotificationAuthorizationContext, MAX_AUDIT_NOTIFICATION_BYTES, MAX_AUDIT_NOTIFICATIONS,
59 UnconfirmedAuditNotificationAuthorizationContext,
60};
61pub use crate::cov::{CovCounters, CovPolicy};
62use crate::cov::{
63 CovNotificationKind, CovSubscription, CovSubscriptionSnapshot, CovSubscriptionTable,
64};
65use crate::life_safety::LifeSafetyOperationAuthorizationContext;
66use crate::{handlers, runtime_clock};
67use confirmed_request_tracker::{
68 ConfirmedRequestAdmission, ConfirmedRequestTracker, PendingConfirmedRequest,
69};
70pub use device_bindings::DeviceBinding;
71use device_bindings::{DeviceBindingTable, register_configured_binding};
72use learned_router_cache::LearnedRouterCache;
73use lso_replay::{LsoAdmission, PendingLsoReplay};
74use notification_transactions::{
75 InitiationRestricted, NotificationTransactions, NotificationWorkerResult,
76 canonical_direct_peer, canonical_routed_peer, run_notification_under_dcc,
77 run_notification_worker,
78};
79use request_services::{DispatchContext, RequestOrigin, RequestServices, UnconfirmedServices};
80use requests::ConfirmedRequestOwnership;
81use requests::confirmed_response::ResponseTarget;
82use segmentation::{ComplexAckParams, SegmentedSendResources};
83
84const MAX_SEG_RECEIVERS: usize = 128;
86
87const MAX_REQUEST_SEGMENTS: usize = 256;
101
102const MAX_SEG_SENDERS: usize = 128;
104
105const MAX_NEG_SEGMENT_ACK_RETRIES: u8 = 3;
107
108const DEFAULT_APDU_SEGMENT_TIMEOUT: Duration = Duration::from_secs(5);
110
111const DEFAULT_APDU_SEGMENT_RETRIES: u8 = MAX_NEG_SEGMENT_ACK_RETRIES;
113
114const DEFAULT_APDU_RETRIES: u8 = 3;
117
118#[derive(Debug, Clone)]
120pub struct TimeSyncData {
121 pub raw_service_data: Bytes,
123 pub is_utc: bool,
125 pub source_mac: MacAddr,
128 pub source_network: Option<NpduAddress>,
130 pub provenance: bacnet_transport::port::TransportProvenance,
133}
134
135mod config;
136pub use config::ServerConfig;
137mod audit_batch_queue;
138mod audit_batch_runtime;
139mod audit_context_preparation;
140mod audit_forwarder;
141#[cfg(test)]
142mod audit_forwarder_tests;
143mod audit_recipient;
144mod audit_recipient_routes;
145mod audit_reporter;
146mod audit_reporter_changes;
147mod audit_send_now;
148mod heap_futures;
149pub use audit_reporter::{AuditReportersConfig, valid_bip_audit_address};
150#[cfg(test)]
151mod audit_reporter_tests;
152
153pub struct ServerBuilder<T: TransportPort = AnyTransport> {
156 config: ServerConfig,
157 db: Option<ObjectDatabase>,
158 transport: Option<T>,
159 configured_device_bindings: Vec<DeviceBinding>,
160}
161
162impl<T: TransportPort + 'static> ServerBuilder<T> {
163 pub fn device(mut self, identity: bacnet_objects::DeviceIdentity) -> Self {
166 self.config.device = identity;
167 self
168 }
169
170 pub fn database(mut self, db: ObjectDatabase) -> Self {
172 self.db = Some(db);
173 self
174 }
175
176 pub fn transport(mut self, transport: T) -> Self {
178 self.transport = Some(transport);
179 self
180 }
181
182 pub fn device_binding(mut self, binding: DeviceBinding) -> Result<Self, Error> {
184 register_configured_binding(&mut self.configured_device_bindings, binding)?;
185 Ok(self)
186 }
187
188 pub fn audit_notification_sink(mut self, sink: ObjectIdentifier) -> Self {
190 self.config.audit_notification_sink = Some(sink);
191 self
192 }
193
194 pub fn enable_fault_detection(mut self, enabled: bool) -> Self {
202 self.config.enable_fault_detection = enabled;
203 self
204 }
205
206 pub fn enable_event_enrollment(mut self, enabled: bool) -> Self {
208 self.config.enable_event_enrollment = enabled;
209 self
210 }
211
212 pub fn event_enrollment_interval_secs(mut self, secs: u64) -> Self {
215 self.config.event_enrollment_interval_secs = secs;
216 self
217 }
218
219 pub fn discovery_policy(mut self, policy: DiscoveryPolicy) -> Self {
221 self.config.discovery_policy = policy;
222 self
223 }
224
225 pub fn cov_policy(mut self, policy: CovPolicy) -> Self {
228 self.config.cov_policy = policy;
229 self
230 }
231
232 pub async fn build(mut self) -> Result<BACnetServer<T>, Error> {
234 let transport = self
235 .transport
236 .ok_or_else(|| Error::Encoding("transport not set on ServerBuilder".into()))?;
237 let db = crate::local_device::prepare_database(
238 &mut self.config,
239 self.db,
240 transport.local_receive_apdu_capacity(),
241 )?;
242 BACnetServer::start_with_clock_mode_and_bindings(
243 self.config,
244 db,
245 transport,
246 Some(ClockConfig::default()),
247 self.configured_device_bindings,
248 )
249 .await
250 }
251}
252
253pub struct BipServerBuilder {
255 config: ServerConfig,
256 db: Option<ObjectDatabase>,
257 configured_device_bindings: Vec<DeviceBinding>,
258 mode: BipMode,
259 multicast: Option<BipMulticast>,
260}
261
262impl BipServerBuilder {
263 pub fn device(mut self, identity: bacnet_objects::DeviceIdentity) -> Self {
266 self.config.device = identity;
267 self
268 }
269
270 pub fn database(mut self, db: ObjectDatabase) -> Self {
272 self.db = Some(db);
273 self
274 }
275
276 pub fn device_binding(mut self, binding: DeviceBinding) -> Result<Self, Error> {
278 register_configured_binding(&mut self.configured_device_bindings, binding)?;
279 Ok(self)
280 }
281
282 pub fn audit_notification_sink(mut self, sink: ObjectIdentifier) -> Self {
284 self.config.audit_notification_sink = Some(sink);
285 self
286 }
287
288 pub fn enable_fault_detection(mut self, enabled: bool) -> Self {
296 self.config.enable_fault_detection = enabled;
297 self
298 }
299
300 pub fn enable_event_enrollment(mut self, enabled: bool) -> Self {
302 self.config.enable_event_enrollment = enabled;
303 self
304 }
305
306 pub fn event_enrollment_interval_secs(mut self, secs: u64) -> Self {
309 self.config.event_enrollment_interval_secs = secs;
310 self
311 }
312
313 pub fn discovery_policy(mut self, policy: DiscoveryPolicy) -> Self {
315 self.config.discovery_policy = policy;
316 self
317 }
318
319 pub fn cov_policy(mut self, policy: CovPolicy) -> Self {
322 self.config.cov_policy = policy;
323 self
324 }
325
326 pub async fn build(mut self) -> Result<BACnetServer<BipTransport>, Error> {
328 let config = &self.config;
329 let mut transport =
330 BipTransport::new(config.interface, config.port, config.broadcast_address);
331 transport.set_share_port_by_address(config.share_port_by_address);
332 transport.set_mode(self.mode);
333 transport.set_multicast(self.multicast)?;
334 let db = crate::local_device::prepare_database(
335 &mut self.config,
336 self.db,
337 transport.local_receive_apdu_capacity(),
338 )?;
339 BACnetServer::start_with_clock_mode_and_bindings(
340 self.config,
341 db,
342 transport,
343 Some(ClockConfig::default()),
344 self.configured_device_bindings,
345 )
346 .await
347 }
348}
349
350type TransportCleanup<T> = JoinHandle<(NetworkLayer<T>, Result<(), Error>)>;
351
352pub struct BACnetServer<T: TransportPort = AnyTransport> {
359 target_audit: Option<Arc<audit_recipient::TargetAudit<T>>>,
360 config: Arc<ServerConfig>,
362 discovery_limiter: Arc<DiscoveryLimiter>,
363 #[allow(dead_code)] time_sync_limiter: Arc<TimeSyncLimiter>,
365 _clock: Option<Arc<ServerClock>>,
367 network: Option<Arc<NetworkLayer<T>>>,
370 broadcaster: Arc<broadcaster::BroadcasterState<T>>,
371 transport_cleanup: Option<TransportCleanup<T>>,
372 transport_cleanup_error: Option<String>,
373 network_number_task: Option<JoinHandle<()>>,
374 db: Arc<RwLock<ObjectDatabase>>,
376 cov_table: Arc<RwLock<CovSubscriptionTable>>,
379 cov_counters: Arc<crate::cov::AtomicCovCounters>,
380 #[allow(dead_code)]
382 seg_ack_senders: Arc<segmented_send::SegmentedSendRegistry>,
383 #[allow(dead_code)]
386 seg_send_permits: Arc<Semaphore>,
387 cov_in_flight: Arc<Semaphore>,
390 learned_routers: Arc<Mutex<LearnedRouterCache>>,
392 notification_transactions: Arc<NotificationTransactions>,
394 confirmed_request_tracker: Arc<ConfirmedRequestTracker>,
396 device_bindings: Arc<RwLock<DeviceBindingTable>>,
398 comm_state: Arc<CommState>,
400 dcc_timer: Arc<Mutex<crate::server::dcc_timer::TimerSlot>>,
403 dcc_outcomes: Arc<dcc_outcomes::DccOutcomes>,
404 event_suppressions: Arc<event_suppression::EventSuppressions>,
406 mutation_decisions: Arc<crate::mutation::MutationDecisions>,
407 dispatch_task: Option<JoinHandle<()>>,
408 request_tasks: Arc<request_tasks::RequestTasks>,
409 cov_purge_task: Option<JoinHandle<()>>,
410 fault_detection_task: Option<JoinHandle<()>>,
411 event_enrollment_task: Option<JoinHandle<()>>,
412 trend_log_task: Option<JoinHandle<()>>,
413 schedule_tick_task: Option<JoinHandle<()>>,
414 intrinsic_reporting_task: Option<JoinHandle<()>>,
416 binary_lighting_operation_task: Option<JoinHandle<()>>,
419 cov_revisit_task: Option<JoinHandle<()>>,
421 local_mac: MacAddr,
422}
423
424pub struct IAmBroadcaster<T: TransportPort> {
431 state: std::sync::Weak<broadcaster::BroadcasterState<T>>,
432}
433
434impl<T: TransportPort> Clone for IAmBroadcaster<T> {
435 fn clone(&self) -> Self {
436 Self {
437 state: self.state.clone(),
438 }
439 }
440}
441
442impl BACnetServer<BipTransport> {
443 pub fn bip_builder() -> BipServerBuilder {
445 BipServerBuilder {
446 config: ServerConfig::default(),
447 db: None,
448 configured_device_bindings: Vec::new(),
449 mode: BipMode::Normal,
450 multicast: None,
451 }
452 }
453}
454
455mod clock;
456mod command_runs;
457mod reinitialize;
458mod time_sync_policy;
459#[doc(hidden)]
460pub use reinitialize::EndpointReinitializeAudit as __endpoint_ReinitializeAudit;
461pub use reinitialize::{ReinitializeContext, ReinitializeHandler};
462mod write_group;
463pub use clock::ClockConfig;
464use clock::ServerClock;
465#[cfg(test)]
466pub(crate) use clock::clocked_test_database;
467use time_sync_policy::{TimeSyncLimiter, request_limiters};
468pub use time_sync_policy::{
469 TimeSyncPolicy, TimeSyncRateLimit, TimeSyncSource, TimeSyncSourceRestriction,
470};
471mod binary_lighting_lifecycle;
472#[cfg(test)]
473mod confirmed_issuance_tests;
474mod confirmed_request_tracker;
475mod cov_clock;
476mod cov_encoding;
477mod cov_fanout;
478mod cov_notifications;
479mod cov_notify_context;
480mod cov_snapshot;
481mod dcc_disable_rate;
482pub(crate) mod dcc_outcomes;
483mod dcc_policy;
484mod lso_replay;
485pub use dcc_disable_rate::DccDisableRateLimit;
486mod dcc_timer;
487pub use dcc_outcomes::DccOutcomeCounters;
488pub use dcc_policy::{DccPolicy, DccSource, DccSourceRestriction};
489use dcc_timer::CommState;
490pub use dcc_timer::DccState;
491mod binding_probes;
492mod device_bindings;
493mod discovery;
494#[doc(hidden)]
495pub use discovery::iam_request_for as discovery_iam_for_test;
496pub use discovery::{DiscoveryCounters, DiscoveryPolicy};
497pub(crate) use discovery::{DiscoveryLimiter, PreCheckDecision, WhoHasTarget};
498mod audit_log_purge;
499mod dispatch;
500mod durable_writes;
501#[doc(hidden)]
502pub use durable_writes::settle_endpoint as __endpoint_settle_durable_writes;
503mod event_delivery;
504mod event_enrollment_lifecycle;
505mod event_forwarding;
506pub use event_forwarding::MAX_FORWARDED_DESTINATIONS;
507mod event_forwarding_repeats;
508mod event_message_policy;
509pub(crate) mod event_notification_payload;
510mod event_notifications;
511mod event_recipient_route;
512mod event_send;
513mod event_suppression;
514pub use event_suppression::EventNotificationCounters;
515mod received_event_log;
516pub use received_event_log::{RECEIVED_EVENT_LOG_RATE, RECEIVED_EVENT_LOG_SOURCES};
517mod confirmed_answer;
518pub(crate) mod event_timestamp;
519mod handles;
520mod learned_router_cache;
521mod lifecycle;
522mod local_authorization;
523pub use local_authorization::LocalAuthorizationResult;
524mod local_writes;
525mod network_port;
526#[cfg(test)]
527mod network_port_tests;
528#[cfg(test)]
531#[path = "../../../bacnet-endpoint/tests/support/port_retry.rs"]
532mod port_retry;
533pub use confirmed_answer::CovAckResult;
534mod remote_writes;
535pub(crate) use remote_writes::RemoteRequestError;
536mod notification_transactions;
537#[doc(hidden)]
538pub use notification_transactions::{
539 AuditFailureContext as __endpoint_AuditFailureContext,
540 AuditFailureQueue as __endpoint_AuditFailureQueue,
541 AuditFailureTicket as __endpoint_AuditFailureTicket,
542 NotificationOperation as __endpoint_NotificationOperation,
543 NotificationReserveError as __endpoint_NotificationReserveError,
544 NotificationTransactions as __endpoint_NotificationTransactions,
545 NotificationWorkerResult as __endpoint_NotificationWorkerResult,
546 canonical_direct_peer as __endpoint_canonical_direct_peer,
547 canonical_routed_peer as __endpoint_canonical_routed_peer,
548 run_notification_worker as __endpoint_run_notification_worker,
549};
550mod requests;
551#[doc(hidden)]
552pub use requests::endpoint_responder::EndpointResponder as __endpoint_EndpointResponder;
553#[cfg(feature = "sc-tls")]
554mod sc_builder;
555#[cfg(test)]
556pub(crate) use requests::{EXECUTED_CONFIRMED, EXECUTED_UNCONFIRMED};
557#[cfg(test)]
558mod audit_notification_tests;
559#[cfg(test)]
560mod unconfirmed_audit_notification_tests;
561#[cfg(feature = "sc-tls")]
562pub use sc_builder::ScServerBuilder;
563mod responses;
564mod segmentation;
565mod segmented_receive;
566mod segmented_send;
567pub(crate) use segmented_send::*;
568mod request_admission;
569mod rpm_budget;
570pub use rpm_budget::ReadPropertyMultipleBudget;
571mod alarm_summary_budget;
572pub use alarm_summary_budget::GetAlarmSummaryBudget;
573mod atomic_read_file_budget;
574mod atomic_write_file_budget;
575mod read_range_budget;
576pub use read_range_budget::ReadRangeBudget;
577mod event_information_budget;
578pub use event_information_budget::GetEventInformationBudget;
579mod enrollment_summary_budget;
580pub use atomic_read_file_budget::AtomicReadFileBudget;
581pub use atomic_write_file_budget::AtomicWriteFileBudget;
582pub use enrollment_summary_budget::GetEnrollmentSummaryBudget;
583#[cfg(test)]
584mod atomic_read_file_tests;
585#[cfg(test)]
586mod atomic_write_file_tests;
587#[cfg(test)]
588mod enrollment_summary_tests;
589mod request_peer;
590mod request_services;
591mod request_tasks;
592pub use request_admission::{RequestAdmissionCounters, RequestAdmissionPolicy};
593mod shutdown;
594pub use shutdown::drop_database_off_runtime;
595
596#[cfg(test)]
597mod access_door_event_tests;
598#[cfg(test)]
599mod access_door_pulse_task_tests;
600#[cfg(test)]
601mod access_zone_event_tests;
602#[cfg(test)]
603mod acknowledge_alarm_tests;
604#[cfg(test)]
605mod active_cov_subscriptions_tests;
606#[cfg(test)]
607mod audit_log_query_tests;
608#[cfg(test)]
609mod averaging_reference_write_tests;
610#[cfg(test)]
611mod averaging_sample_tests;
612#[cfg(test)]
613mod binary_lighting_task_tests;
614#[cfg(test)]
615mod channel_member_concurrency_tests;
616#[cfg(test)]
617mod channel_reliability_tests;
618#[cfg(test)]
619mod channel_remote_datatype_tests;
620#[cfg(test)]
621mod channel_remote_write_tests;
622#[cfg(test)]
623mod channel_run_tests;
624#[cfg(test)]
625mod channel_wire_tests;
626#[cfg(test)]
627mod color_channel_member_tests;
628#[cfg(test)]
629mod color_engine_task_tests;
630#[cfg(test)]
631mod command_action_run_tests;
632#[cfg(test)]
633mod command_action_wire_tests;
634#[cfg(test)]
635mod command_remote_write_tests;
636#[cfg(test)]
637mod command_run_cancel_tests;
638#[cfg(test)]
639mod command_run_stop_tests;
640#[cfg(test)]
641mod confirmed_broadcast_tests;
642#[cfg(test)]
643mod cov_background_tests;
644#[cfg(test)]
645mod cov_budget_tests;
646#[cfg(test)]
647mod cov_confirmed_baseline_tests;
648#[cfg(test)]
649mod cov_confirmed_context_tests;
650#[cfg(test)]
651mod cov_multiple_admission_tests;
652#[cfg(test)]
653mod cov_notifications_tests;
654#[cfg(test)]
655mod cov_quota_tests;
656#[cfg(test)]
657mod cov_timed_capture_order_tests;
658#[cfg(test)]
659mod cov_timed_chunk_tests;
660#[cfg(test)]
661mod cov_timed_deadline_tests;
662#[cfg(test)]
663mod cov_timed_multiple_tests;
664#[cfg(test)]
665mod cov_timed_producer_tests;
666#[cfg(test)]
667mod cov_timed_value_split_tests;
668#[cfg(test)]
669mod cov_untimed_split_tests;
670#[cfg(test)]
671mod cov_wire_test_support;
672#[cfg(test)]
673mod dcc_event_detection_tests;
674#[cfg(test)]
675mod device_bindings_tests;
676#[cfg(test)]
677mod device_recipient_routing_tests;
678#[cfg(all(test, feature = "sc-tls"))]
679mod direct_principal_tests;
680#[cfg(test)]
681mod discovery_dcc_tests;
682#[cfg(test)]
683mod discovery_tests;
684#[cfg(test)]
685mod event_confirmed_routing_tests;
686#[cfg(test)]
687mod event_enable_distribution_tests;
688#[cfg(test)]
689mod event_enrollment_task_tests;
690#[cfg(test)]
691mod event_forwarding_bounds_tests;
692#[cfg(test)]
693mod event_forwarding_cap_tests;
694#[cfg(test)]
695mod event_forwarding_origin_tests;
696#[cfg(test)]
697mod event_forwarding_rule_tests;
698#[cfg(test)]
699mod event_forwarding_tests;
700#[cfg(test)]
701mod event_log_notification_tests;
702#[cfg(test)]
703mod event_network_priority_tests;
704#[cfg(test)]
705mod event_notifications_tests;
706#[cfg(test)]
707mod event_recipient_routing_tests;
708#[cfg(test)]
709mod life_safety_application_tests;
710#[cfg(test)]
711mod life_safety_cov_tests;
712#[cfg(test)]
713mod life_safety_operation_replay_tests;
714#[cfg(test)]
715mod life_safety_operation_tests;
716#[cfg(test)]
717mod lighting_command_member_tests;
718#[cfg(test)]
719mod lighting_engine_task_tests;
720#[cfg(test)]
721mod lighting_present_value_tests;
722#[cfg(test)]
723mod list_element_event_tests;
724#[cfg(test)]
725mod local_network_number_tests;
726#[cfg(test)]
727mod local_network_outbound_tests;
728#[cfg(test)]
729mod log_reference_resize_tests;
730#[cfg(test)]
731mod loop_controlled_variable_tests;
732#[cfg(test)]
733mod loop_cov_tests;
734#[cfg(test)]
735mod mistagged_request_wire_tests;
736#[cfg(test)]
737mod noncommandable_null_cov_tests;
738#[cfg(test)]
739mod notification_dcc_tests;
740#[cfg(test)]
741mod notification_transactions_tests;
742#[cfg(test)]
743mod pulse_converter_cov_tests;
744#[cfg(test)]
745mod pulse_converter_reference_tests;
746#[cfg(test)]
747mod rb07_provenance_tests;
748#[cfg(test)]
749mod reference_write_wire_tests;
750#[cfg(test)]
751mod remote_write_answer_tests;
752#[cfg(test)]
753mod remote_write_discovery_tests;
754#[cfg(test)]
755mod run_cycle_tests;
756#[cfg(test)]
757mod schedule_create_retry_tests;
758#[cfg(test)]
759mod schedule_reference_list_tests;
760#[cfg(test)]
761mod schedule_reference_write_tests;
762#[cfg(test)]
763mod schedule_write_tests;
764#[cfg(test)]
765mod segmentation_tests;
766#[cfg(test)]
767mod staging_cov_tests;
768#[cfg(test)]
769mod staging_reference_write_tests;
770#[cfg(test)]
771mod subscribed_recipients_expiry_tests;
772#[cfg(test)]
773mod table_13_1_cov_tests;
774#[cfg(test)]
775pub(crate) mod test_forwarder;
776#[cfg(test)]
777pub(crate) mod test_transport;
778#[cfg(test)]
779mod tests;
780#[cfg(test)]
781mod trailing_octet_wire_tests;
782#[cfg(test)]
783mod truncated_request_wire_tests;
784#[cfg(test)]
785mod value_cov_increment_tests;
786#[cfg(test)]
787mod value_source_local_tests;
788#[cfg(test)]
789mod warn_spy;
790
791impl<T: TransportPort + 'static> BACnetServer<T> {
792 pub fn discovery_counters(&self) -> DiscoveryCounters {
794 self.discovery_limiter.counters()
795 }
796
797 pub fn cov_counters(&self) -> CovCounters {
799 self.cov_counters.snapshot()
800 }
801
802 pub fn mutation_decision_counters(&self) -> crate::mutation::MutationDecisionCounters {
806 self.mutation_decisions.snapshot()
807 }
808
809 pub async fn remove_peer_subscriptions(
813 &self,
814 mac: &[u8],
815 network: Option<&NpduAddress>,
816 ) -> usize {
817 let mut table = self.cov_table.write().await;
818 table.remove_peer_subscriptions(mac, network)
819 }
820}
821
822#[cfg(test)]
823mod cov_identity_completion_tests;
824
825mod broadcaster;
826#[cfg(test)]
827mod r7_reply_tests;