hive_btle/platform/
mod.rs1#[cfg(not(feature = "std"))]
23use alloc::{boxed::Box, format, string::String, string::ToString, vec::Vec};
24
25use async_trait::async_trait;
26
27use crate::config::{BleConfig, BlePhy, DiscoveryConfig};
28use crate::error::Result;
29use crate::transport::BleConnection;
30use crate::NodeId;
31
32#[cfg(all(feature = "linux", target_os = "linux"))]
34pub mod linux;
35
36#[cfg(feature = "android")]
37pub mod android;
38
39#[cfg(any(feature = "macos", feature = "ios"))]
40pub mod apple;
41
42#[cfg(feature = "windows")]
43pub mod windows;
44
45#[cfg(feature = "embedded")]
46pub mod embedded;
47
48#[cfg(feature = "esp32")]
49pub mod esp32;
50
51#[cfg(feature = "std")]
53pub mod mock;
54
55#[derive(Debug, Clone)]
57pub struct DiscoveredDevice {
58 pub address: String,
60 pub name: Option<String>,
62 pub rssi: i8,
64 pub is_hive_node: bool,
66 pub node_id: Option<NodeId>,
68 pub adv_data: Vec<u8>,
70}
71
72pub type DiscoveryCallback = std::sync::Arc<dyn Fn(DiscoveredDevice) + Send + Sync>;
74
75pub type ConnectionCallback = std::sync::Arc<dyn Fn(NodeId, ConnectionEvent) + Send + Sync>;
77
78#[derive(Debug, Clone)]
80pub enum ConnectionEvent {
81 Connected {
83 mtu: u16,
85 phy: BlePhy,
87 },
88 Disconnected {
90 reason: DisconnectReason,
92 },
93 ServicesDiscovered {
95 has_hive_service: bool,
97 },
98 DataReceived {
100 data: Vec<u8>,
102 },
103 MtuChanged {
105 mtu: u16,
107 },
108 PhyChanged {
110 phy: BlePhy,
112 },
113 RssiUpdated {
115 rssi: i8,
117 },
118}
119
120#[derive(Debug, Clone, Copy, PartialEq, Eq)]
122pub enum DisconnectReason {
123 LocalRequest,
125 RemoteRequest,
127 Timeout,
129 LinkLoss,
131 ConnectionFailed,
133 Unknown,
135}
136
137#[async_trait]
142pub trait BleAdapter: Send + Sync {
143 async fn init(&mut self, config: &BleConfig) -> Result<()>;
145
146 async fn start(&self) -> Result<()>;
148
149 async fn stop(&self) -> Result<()>;
151
152 fn is_powered(&self) -> bool;
154
155 fn address(&self) -> Option<String>;
157
158 async fn start_scan(&self, config: &DiscoveryConfig) -> Result<()>;
162
163 async fn stop_scan(&self) -> Result<()>;
165
166 async fn start_advertising(&self, config: &DiscoveryConfig) -> Result<()>;
168
169 async fn stop_advertising(&self) -> Result<()>;
171
172 fn set_discovery_callback(&mut self, callback: Option<DiscoveryCallback>);
174
175 async fn connect(&self, peer_id: &NodeId) -> Result<Box<dyn BleConnection>>;
179
180 async fn disconnect(&self, peer_id: &NodeId) -> Result<()>;
182
183 fn get_connection(&self, peer_id: &NodeId) -> Option<Box<dyn BleConnection>>;
185
186 fn peer_count(&self) -> usize;
188
189 fn connected_peers(&self) -> Vec<NodeId>;
191
192 fn set_connection_callback(&mut self, callback: Option<ConnectionCallback>);
194
195 async fn register_gatt_service(&self) -> Result<()>;
199
200 async fn unregister_gatt_service(&self) -> Result<()>;
202
203 fn supports_coded_phy(&self) -> bool;
207
208 fn supports_extended_advertising(&self) -> bool;
210
211 fn max_mtu(&self) -> u16;
213
214 fn max_connections(&self) -> u8;
216}
217
218#[derive(Debug, Default)]
220pub struct StubAdapter {
221 powered: bool,
222}
223
224#[async_trait]
225impl BleAdapter for StubAdapter {
226 async fn init(&mut self, _config: &BleConfig) -> Result<()> {
227 self.powered = true;
228 Ok(())
229 }
230
231 async fn start(&self) -> Result<()> {
232 Ok(())
233 }
234
235 async fn stop(&self) -> Result<()> {
236 Ok(())
237 }
238
239 fn is_powered(&self) -> bool {
240 self.powered
241 }
242
243 fn address(&self) -> Option<String> {
244 Some("00:00:00:00:00:00".to_string())
245 }
246
247 async fn start_scan(&self, _config: &DiscoveryConfig) -> Result<()> {
248 Ok(())
249 }
250
251 async fn stop_scan(&self) -> Result<()> {
252 Ok(())
253 }
254
255 async fn start_advertising(&self, _config: &DiscoveryConfig) -> Result<()> {
256 Ok(())
257 }
258
259 async fn stop_advertising(&self) -> Result<()> {
260 Ok(())
261 }
262
263 fn set_discovery_callback(&mut self, _callback: Option<DiscoveryCallback>) {}
264
265 async fn connect(&self, peer_id: &NodeId) -> Result<Box<dyn BleConnection>> {
266 Err(crate::error::BleError::NotSupported(format!(
267 "Stub adapter cannot connect to {}",
268 peer_id
269 )))
270 }
271
272 async fn disconnect(&self, _peer_id: &NodeId) -> Result<()> {
273 Ok(())
274 }
275
276 fn get_connection(&self, _peer_id: &NodeId) -> Option<Box<dyn BleConnection>> {
277 None
278 }
279
280 fn peer_count(&self) -> usize {
281 0
282 }
283
284 fn connected_peers(&self) -> Vec<NodeId> {
285 Vec::new()
286 }
287
288 fn set_connection_callback(&mut self, _callback: Option<ConnectionCallback>) {}
289
290 async fn register_gatt_service(&self) -> Result<()> {
291 Ok(())
292 }
293
294 async fn unregister_gatt_service(&self) -> Result<()> {
295 Ok(())
296 }
297
298 fn supports_coded_phy(&self) -> bool {
299 false
300 }
301
302 fn supports_extended_advertising(&self) -> bool {
303 false
304 }
305
306 fn max_mtu(&self) -> u16 {
307 23
308 }
309
310 fn max_connections(&self) -> u8 {
311 0
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318
319 #[tokio::test]
320 async fn test_stub_adapter() {
321 let mut adapter = StubAdapter::default();
322 assert!(!adapter.is_powered());
323
324 adapter.init(&BleConfig::default()).await.unwrap();
325 assert!(adapter.is_powered());
326 assert_eq!(adapter.peer_count(), 0);
327 assert!(!adapter.supports_coded_phy());
328 }
329}