servo_bluetooth/
adapter.rs1use std::error::Error;
6use std::sync::Arc;
7
8#[cfg(feature = "bluetooth-test")]
9use blurmock::fake_adapter::FakeBluetoothAdapter;
10#[cfg(feature = "bluetooth-test")]
11use blurmock::fake_device::FakeBluetoothDevice;
12#[cfg(feature = "bluetooth-test")]
13use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
14#[cfg(feature = "native-bluetooth")]
15use btleplug::api::{Central, CentralState, Manager};
16#[cfg(feature = "native-bluetooth")]
17use btleplug::platform::{Adapter, Manager as PlatformManager};
18
19use super::bluetooth::{BluetoothDevice, BluetoothDiscoverySession};
20use crate::macros::get_inner_and_call_test_func;
21
22#[cfg(feature = "native-bluetooth")]
23#[derive(Clone, Debug)]
24pub struct BtleplugAdapter {
25 adapter: Adapter,
26}
27
28#[cfg(feature = "native-bluetooth")]
29impl BtleplugAdapter {
30 pub async fn new() -> Result<Self, Box<dyn Error>> {
31 let manager = PlatformManager::new().await?;
32 let adapters = manager.adapters().await?;
33 let adapter = adapters
34 .into_iter()
35 .next()
36 .ok_or_else(|| btleplug::Error::NoAdapterAvailable)?;
37 Ok(BtleplugAdapter { adapter })
38 }
39
40 pub async fn get_address(&self) -> Result<String, Box<dyn Error>> {
41 Ok(self.adapter.adapter_info().await?)
42 }
43
44 pub async fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
45 let state = self.adapter.adapter_state().await?;
46 Ok(state == CentralState::PoweredOn)
47 }
48
49 pub async fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<dyn Error>> {
50 let peripherals = self.adapter.peripherals().await?;
51 Ok(peripherals
52 .into_iter()
53 .map(|p| BluetoothDevice::Btleplug(super::bluetooth::BtleplugDevice { peripheral: p }))
54 .collect())
55 }
56
57 pub fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
58 Ok(BluetoothDiscoverySession::Btleplug(
59 super::bluetooth::BtleplugDiscoverySession {
60 adapter: self.adapter.clone(),
61 },
62 ))
63 }
64}
65
66#[derive(Clone, Debug)]
67pub enum BluetoothAdapter {
68 #[cfg(feature = "native-bluetooth")]
69 Btleplug(BtleplugAdapter),
70 #[cfg(feature = "bluetooth-test")]
71 Mock(Arc<FakeBluetoothAdapter>),
72}
73
74impl BluetoothAdapter {
75 #[cfg(feature = "native-bluetooth")]
76 pub async fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
77 Ok(Self::Btleplug(BtleplugAdapter::new().await?))
78 }
79
80 #[cfg(not(feature = "native-bluetooth"))]
81 pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
82 Err(Box::from("Bluetooth not supported on this platform"))
83 }
84
85 #[cfg(feature = "bluetooth-test")]
86 pub fn new_mock() -> Result<BluetoothAdapter, Box<dyn Error>> {
87 Ok(Self::Mock(FakeBluetoothAdapter::new_empty()))
88 }
89
90 pub async fn get_address(&self) -> Result<String, Box<dyn Error>> {
91 match self {
92 #[cfg(feature = "native-bluetooth")]
93 Self::Btleplug(inner) => inner.get_address().await,
94 #[cfg(feature = "bluetooth-test")]
95 Self::Mock(inner) => inner.get_address(),
96 }
97 }
98
99 pub async fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
100 match self {
101 #[cfg(feature = "native-bluetooth")]
102 Self::Btleplug(inner) => inner.is_powered().await,
103 #[cfg(feature = "bluetooth-test")]
104 Self::Mock(inner) => inner.is_powered(),
105 }
106 }
107
108 pub async fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<dyn Error>> {
109 match self {
110 #[cfg(feature = "native-bluetooth")]
111 Self::Btleplug(inner) => inner.get_devices().await,
112 #[cfg(feature = "bluetooth-test")]
113 Self::Mock(inner) => {
114 let device_list = inner.get_device_list()?;
115 Ok(device_list
116 .into_iter()
117 .map(|device| {
118 BluetoothDevice::Mock(FakeBluetoothDevice::new_empty(inner.clone(), device))
119 })
120 .collect())
121 },
122 }
123 }
124
125 pub fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
126 match self {
127 #[cfg(feature = "native-bluetooth")]
128 Self::Btleplug(inner) => inner.create_discovery_session(),
129 #[cfg(feature = "bluetooth-test")]
130 Self::Mock(inner) => Ok(BluetoothDiscoverySession::Mock(Arc::new(
131 FakeBluetoothDiscoverySession::create_session(inner.clone())?,
132 ))),
133 }
134 }
135
136 pub fn create_mock_device(&self, _device: String) -> Result<BluetoothDevice, Box<dyn Error>> {
137 match self {
138 #[cfg(feature = "bluetooth-test")]
139 Self::Mock(inner) => Ok(BluetoothDevice::Mock(FakeBluetoothDevice::new_empty(
140 inner.clone(),
141 _device,
142 ))),
143 #[cfg(feature = "native-bluetooth")]
144 _ => Err(Box::from("Test functions not supported on real devices")),
145 }
146 }
147
148 #[cfg(feature = "bluetooth-test")]
149 pub fn set_name(&self, name: String) -> Result<(), Box<dyn Error>> {
150 get_inner_and_call_test_func!(self, BluetoothAdapter, set_name, name)
151 }
152
153 #[cfg(feature = "bluetooth-test")]
154 pub fn set_powered(&self, powered: bool) -> Result<(), Box<dyn Error>> {
155 get_inner_and_call_test_func!(self, BluetoothAdapter, set_powered, powered)
156 }
157
158 #[cfg(feature = "bluetooth-test")]
159 pub fn is_present(&self) -> Result<bool, Box<dyn Error>> {
160 get_inner_and_call_test_func!(self, BluetoothAdapter, is_present)
161 }
162
163 #[cfg(feature = "bluetooth-test")]
164 pub fn set_present(&self, present: bool) -> Result<(), Box<dyn Error>> {
165 get_inner_and_call_test_func!(self, BluetoothAdapter, set_present, present)
166 }
167
168 #[cfg(feature = "bluetooth-test")]
169 pub fn set_discoverable(&self, discoverable: bool) -> Result<(), Box<dyn Error>> {
170 get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable, discoverable)
171 }
172}