Skip to main content

fips_core/transport/ble/
stats.rs

1//! BLE transport statistics.
2
3use portable_atomic::{AtomicU64, Ordering};
4
5use serde::Serialize;
6
7/// Statistics for a BLE transport instance.
8///
9/// Uses atomic counters for lock-free updates from per-connection
10/// receive loops and the send path concurrently.
11pub struct BleStats {
12    pub packets_sent: AtomicU64,
13    pub bytes_sent: AtomicU64,
14    pub packets_recv: AtomicU64,
15    pub bytes_recv: AtomicU64,
16    pub send_errors: AtomicU64,
17    pub recv_errors: AtomicU64,
18    pub mtu_exceeded: AtomicU64,
19    pub connections_established: AtomicU64,
20    pub connections_accepted: AtomicU64,
21    pub connections_rejected: AtomicU64,
22    pub connect_timeouts: AtomicU64,
23    pub pool_evictions: AtomicU64,
24    pub advertisements_sent: AtomicU64,
25    pub scan_results: AtomicU64,
26}
27
28impl BleStats {
29    /// Create a new stats instance with all counters at zero.
30    pub fn new() -> Self {
31        Self {
32            packets_sent: AtomicU64::new(0),
33            bytes_sent: AtomicU64::new(0),
34            packets_recv: AtomicU64::new(0),
35            bytes_recv: AtomicU64::new(0),
36            send_errors: AtomicU64::new(0),
37            recv_errors: AtomicU64::new(0),
38            mtu_exceeded: AtomicU64::new(0),
39            connections_established: AtomicU64::new(0),
40            connections_accepted: AtomicU64::new(0),
41            connections_rejected: AtomicU64::new(0),
42            connect_timeouts: AtomicU64::new(0),
43            pool_evictions: AtomicU64::new(0),
44            advertisements_sent: AtomicU64::new(0),
45            scan_results: AtomicU64::new(0),
46        }
47    }
48
49    /// Record a successful send.
50    pub fn record_send(&self, bytes: usize) {
51        self.packets_sent.fetch_add(1, Ordering::Relaxed);
52        self.bytes_sent.fetch_add(bytes as u64, Ordering::Relaxed);
53    }
54
55    /// Record a successful receive.
56    pub fn record_recv(&self, bytes: usize) {
57        self.packets_recv.fetch_add(1, Ordering::Relaxed);
58        self.bytes_recv.fetch_add(bytes as u64, Ordering::Relaxed);
59    }
60
61    /// Record a send error.
62    pub fn record_send_error(&self) {
63        self.send_errors.fetch_add(1, Ordering::Relaxed);
64    }
65
66    /// Record a receive error.
67    pub fn record_recv_error(&self) {
68        self.recv_errors.fetch_add(1, Ordering::Relaxed);
69    }
70
71    /// Record an MTU exceeded rejection.
72    pub fn record_mtu_exceeded(&self) {
73        self.mtu_exceeded.fetch_add(1, Ordering::Relaxed);
74    }
75
76    /// Record a successful outbound connection.
77    pub fn record_connection_established(&self) {
78        self.connections_established.fetch_add(1, Ordering::Relaxed);
79    }
80
81    /// Record a successful inbound connection.
82    pub fn record_connection_accepted(&self) {
83        self.connections_accepted.fetch_add(1, Ordering::Relaxed);
84    }
85
86    /// Record a rejected inbound connection (pool full).
87    pub fn record_connection_rejected(&self) {
88        self.connections_rejected.fetch_add(1, Ordering::Relaxed);
89    }
90
91    /// Record a connect timeout.
92    pub fn record_connect_timeout(&self) {
93        self.connect_timeouts.fetch_add(1, Ordering::Relaxed);
94    }
95
96    /// Record a pool eviction (non-static peer displaced).
97    pub fn record_pool_eviction(&self) {
98        self.pool_evictions.fetch_add(1, Ordering::Relaxed);
99    }
100
101    /// Record an advertisement broadcast.
102    pub fn record_advertisement(&self) {
103        self.advertisements_sent.fetch_add(1, Ordering::Relaxed);
104    }
105
106    /// Record a scan result received.
107    pub fn record_scan_result(&self) {
108        self.scan_results.fetch_add(1, Ordering::Relaxed);
109    }
110
111    /// Take a snapshot of all counters.
112    pub fn snapshot(&self) -> BleStatsSnapshot {
113        BleStatsSnapshot {
114            packets_sent: self.packets_sent.load(Ordering::Relaxed),
115            bytes_sent: self.bytes_sent.load(Ordering::Relaxed),
116            packets_recv: self.packets_recv.load(Ordering::Relaxed),
117            bytes_recv: self.bytes_recv.load(Ordering::Relaxed),
118            send_errors: self.send_errors.load(Ordering::Relaxed),
119            recv_errors: self.recv_errors.load(Ordering::Relaxed),
120            mtu_exceeded: self.mtu_exceeded.load(Ordering::Relaxed),
121            connections_established: self.connections_established.load(Ordering::Relaxed),
122            connections_accepted: self.connections_accepted.load(Ordering::Relaxed),
123            connections_rejected: self.connections_rejected.load(Ordering::Relaxed),
124            connect_timeouts: self.connect_timeouts.load(Ordering::Relaxed),
125            pool_evictions: self.pool_evictions.load(Ordering::Relaxed),
126            advertisements_sent: self.advertisements_sent.load(Ordering::Relaxed),
127            scan_results: self.scan_results.load(Ordering::Relaxed),
128        }
129    }
130}
131
132impl Default for BleStats {
133    fn default() -> Self {
134        Self::new()
135    }
136}
137
138/// Point-in-time snapshot of BLE stats (non-atomic, copyable).
139#[derive(Clone, Debug, Default, Serialize)]
140pub struct BleStatsSnapshot {
141    pub packets_sent: u64,
142    pub bytes_sent: u64,
143    pub packets_recv: u64,
144    pub bytes_recv: u64,
145    pub send_errors: u64,
146    pub recv_errors: u64,
147    pub mtu_exceeded: u64,
148    pub connections_established: u64,
149    pub connections_accepted: u64,
150    pub connections_rejected: u64,
151    pub connect_timeouts: u64,
152    pub pool_evictions: u64,
153    pub advertisements_sent: u64,
154    pub scan_results: u64,
155}