hive_btle/platform/
mod.rs1#[cfg(not(feature = "std"))]
38use alloc::{boxed::Box, format, string::String, string::ToString, vec::Vec};
39
40use async_trait::async_trait;
41
42use crate::config::{BleConfig, BlePhy, DiscoveryConfig};
43use crate::error::Result;
44use crate::transport::BleConnection;
45use crate::NodeId;
46
47#[cfg(all(feature = "linux", target_os = "linux"))]
49pub mod linux;
50
51#[cfg(feature = "android")]
52pub mod android;
53
54#[cfg(any(feature = "macos", feature = "ios"))]
55pub mod apple;
56
57#[cfg(feature = "windows")]
58pub mod windows;
59
60#[cfg(feature = "embedded")]
61pub mod embedded;
62
63#[cfg(feature = "esp32")]
64pub mod esp32;
65
66#[cfg(feature = "std")]
68pub mod mock;
69
70#[derive(Debug, Clone)]
72pub struct DiscoveredDevice {
73 pub address: String,
75 pub name: Option<String>,
77 pub rssi: i8,
79 pub is_hive_node: bool,
81 pub node_id: Option<NodeId>,
83 pub adv_data: Vec<u8>,
85}
86
87pub type DiscoveryCallback = std::sync::Arc<dyn Fn(DiscoveredDevice) + Send + Sync>;
89
90pub type ConnectionCallback = std::sync::Arc<dyn Fn(NodeId, ConnectionEvent) + Send + Sync>;
92
93#[derive(Debug, Clone)]
95pub enum ConnectionEvent {
96 Connected {
98 mtu: u16,
100 phy: BlePhy,
102 },
103 Disconnected {
105 reason: DisconnectReason,
107 },
108 ServicesDiscovered {
110 has_hive_service: bool,
112 },
113 DataReceived {
115 data: Vec<u8>,
117 },
118 MtuChanged {
120 mtu: u16,
122 },
123 PhyChanged {
125 phy: BlePhy,
127 },
128 RssiUpdated {
130 rssi: i8,
132 },
133}
134
135#[derive(Debug, Clone, Copy, PartialEq, Eq)]
137pub enum DisconnectReason {
138 LocalRequest,
140 RemoteRequest,
142 Timeout,
144 LinkLoss,
146 ConnectionFailed,
148 Unknown,
150}
151
152#[async_trait]
157pub trait BleAdapter: Send + Sync {
158 async fn init(&mut self, config: &BleConfig) -> Result<()>;
160
161 async fn start(&self) -> Result<()>;
163
164 async fn stop(&self) -> Result<()>;
166
167 fn is_powered(&self) -> bool;
169
170 fn address(&self) -> Option<String>;
172
173 async fn start_scan(&self, config: &DiscoveryConfig) -> Result<()>;
177
178 async fn stop_scan(&self) -> Result<()>;
180
181 async fn start_advertising(&self, config: &DiscoveryConfig) -> Result<()>;
183
184 async fn stop_advertising(&self) -> Result<()>;
186
187 fn set_discovery_callback(&mut self, callback: Option<DiscoveryCallback>);
189
190 async fn connect(&self, peer_id: &NodeId) -> Result<Box<dyn BleConnection>>;
194
195 async fn disconnect(&self, peer_id: &NodeId) -> Result<()>;
197
198 fn get_connection(&self, peer_id: &NodeId) -> Option<Box<dyn BleConnection>>;
200
201 fn peer_count(&self) -> usize;
203
204 fn connected_peers(&self) -> Vec<NodeId>;
206
207 fn set_connection_callback(&mut self, callback: Option<ConnectionCallback>);
209
210 async fn register_gatt_service(&self) -> Result<()>;
214
215 async fn unregister_gatt_service(&self) -> Result<()>;
217
218 fn supports_coded_phy(&self) -> bool;
222
223 fn supports_extended_advertising(&self) -> bool;
225
226 fn max_mtu(&self) -> u16;
228
229 fn max_connections(&self) -> u8;
231}
232
233#[derive(Debug, Default)]
235pub struct StubAdapter {
236 powered: bool,
237}
238
239#[async_trait]
240impl BleAdapter for StubAdapter {
241 async fn init(&mut self, _config: &BleConfig) -> Result<()> {
242 self.powered = true;
243 Ok(())
244 }
245
246 async fn start(&self) -> Result<()> {
247 Ok(())
248 }
249
250 async fn stop(&self) -> Result<()> {
251 Ok(())
252 }
253
254 fn is_powered(&self) -> bool {
255 self.powered
256 }
257
258 fn address(&self) -> Option<String> {
259 Some("00:00:00:00:00:00".to_string())
260 }
261
262 async fn start_scan(&self, _config: &DiscoveryConfig) -> Result<()> {
263 Ok(())
264 }
265
266 async fn stop_scan(&self) -> Result<()> {
267 Ok(())
268 }
269
270 async fn start_advertising(&self, _config: &DiscoveryConfig) -> Result<()> {
271 Ok(())
272 }
273
274 async fn stop_advertising(&self) -> Result<()> {
275 Ok(())
276 }
277
278 fn set_discovery_callback(&mut self, _callback: Option<DiscoveryCallback>) {}
279
280 async fn connect(&self, peer_id: &NodeId) -> Result<Box<dyn BleConnection>> {
281 Err(crate::error::BleError::NotSupported(format!(
282 "Stub adapter cannot connect to {}",
283 peer_id
284 )))
285 }
286
287 async fn disconnect(&self, _peer_id: &NodeId) -> Result<()> {
288 Ok(())
289 }
290
291 fn get_connection(&self, _peer_id: &NodeId) -> Option<Box<dyn BleConnection>> {
292 None
293 }
294
295 fn peer_count(&self) -> usize {
296 0
297 }
298
299 fn connected_peers(&self) -> Vec<NodeId> {
300 Vec::new()
301 }
302
303 fn set_connection_callback(&mut self, _callback: Option<ConnectionCallback>) {}
304
305 async fn register_gatt_service(&self) -> Result<()> {
306 Ok(())
307 }
308
309 async fn unregister_gatt_service(&self) -> Result<()> {
310 Ok(())
311 }
312
313 fn supports_coded_phy(&self) -> bool {
314 false
315 }
316
317 fn supports_extended_advertising(&self) -> bool {
318 false
319 }
320
321 fn max_mtu(&self) -> u16 {
322 23
323 }
324
325 fn max_connections(&self) -> u8 {
326 0
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[tokio::test]
335 async fn test_stub_adapter() {
336 let mut adapter = StubAdapter::default();
337 assert!(!adapter.is_powered());
338
339 adapter.init(&BleConfig::default()).await.unwrap();
340 assert!(adapter.is_powered());
341 assert_eq!(adapter.peer_count(), 0);
342 assert!(!adapter.supports_coded_phy());
343 }
344}