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