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