btleplug/bluez/
adapter.rs1use super::peripheral::{Peripheral, PeripheralId};
2use crate::api::{Central, CentralEvent, CentralState, ScanFilter};
3use crate::{Error, Result};
4use async_trait::async_trait;
5use bluez_async::{
6 AdapterEvent, AdapterId, BluetoothError, BluetoothEvent, BluetoothSession, DeviceEvent,
7 DiscoveryFilter, Transport,
8};
9use futures::stream::{self, Stream, StreamExt};
10use std::pin::Pin;
11
12#[derive(Clone, Debug)]
14pub struct Adapter {
15 session: BluetoothSession,
16 adapter: AdapterId,
17}
18
19impl Adapter {
20 pub(crate) fn new(session: BluetoothSession, adapter: AdapterId) -> Self {
21 Self { session, adapter }
22 }
23}
24
25fn get_central_state(powered: bool) -> CentralState {
26 match powered {
27 true => CentralState::PoweredOn,
28 false => CentralState::PoweredOff,
29 }
30}
31
32#[async_trait]
33impl Central for Adapter {
34 type Peripheral = Peripheral;
35
36 async fn events(&self) -> Result<Pin<Box<dyn Stream<Item = CentralEvent> + Send>>> {
37 let events = self.session.adapter_event_stream(&self.adapter).await?;
41
42 let devices = self.session.get_devices().await?;
44 let adapter_id = self.adapter.clone();
45 let initial_events = stream::iter(
46 devices
47 .into_iter()
48 .filter(move |device| device.id.adapter() == adapter_id)
49 .flat_map(|device| {
50 let peripheral_id: PeripheralId = device.id.into();
51 let mut events = vec![CentralEvent::DeviceDiscovered(peripheral_id.clone())];
52 if !device.services.is_empty() {
53 events.push(CentralEvent::ServicesAdvertisement {
54 id: peripheral_id.clone(),
55 services: device.services,
56 });
57 }
58 if device.connected {
59 events.push(CentralEvent::DeviceConnected(peripheral_id));
60 }
61 events.into_iter()
62 }),
63 );
64
65 let session = self.session.clone();
66 let adapter_id = self.adapter.clone();
67 let events = events
68 .filter_map(move |event| central_events(event, session.clone(), adapter_id.clone()))
69 .flat_map(stream::iter);
70
71 Ok(Box::pin(initial_events.chain(events)))
72 }
73
74 async fn start_scan(&self, filter: ScanFilter) -> Result<()> {
75 let filter = DiscoveryFilter {
76 service_uuids: filter.services,
77 duplicate_data: Some(true),
78 transport: Some(Transport::Auto),
79 ..Default::default()
80 };
81 self.session
82 .start_discovery_on_adapter_with_filter(&self.adapter, &filter)
83 .await?;
84 Ok(())
85 }
86
87 async fn stop_scan(&self) -> Result<()> {
88 self.session
89 .stop_discovery_on_adapter(&self.adapter)
90 .await?;
91 Ok(())
92 }
93
94 async fn peripherals(&self) -> Result<Vec<Peripheral>> {
95 let devices = self.session.get_devices_on_adapter(&self.adapter).await?;
96 Ok(devices
97 .into_iter()
98 .map(|device| Peripheral::new(self.session.clone(), device))
99 .collect())
100 }
101
102 async fn peripheral(&self, id: &PeripheralId) -> Result<Peripheral> {
103 let device = self.session.get_device_info(&id.0).await.map_err(|e| {
104 if let BluetoothError::DbusError(_) = e {
105 Error::DeviceNotFound
106 } else {
107 e.into()
108 }
109 })?;
110 Ok(Peripheral::new(self.session.clone(), device))
111 }
112
113 async fn add_peripheral(&self, _address: &PeripheralId) -> Result<Peripheral> {
114 Err(Error::NotSupported(
115 "Can't add a Peripheral from a PeripheralId".to_string(),
116 ))
117 }
118
119 async fn clear_peripherals(&self) -> Result<()> {
120 Ok(())
122 }
123
124 async fn adapter_info(&self) -> Result<String> {
125 let adapter_info = self.session.get_adapter_info(&self.adapter).await?;
126 Ok(format!("{} ({})", adapter_info.id, adapter_info.modalias))
127 }
128
129 async fn adapter_state(&self) -> Result<CentralState> {
130 let mut powered = false;
131 if let Ok(info) = self.session.get_adapter_info(&self.adapter).await {
132 powered = info.powered;
133 }
134 Ok(get_central_state(powered))
135 }
136}
137
138impl From<BluetoothError> for Error {
139 fn from(error: BluetoothError) -> Self {
140 Error::Other(Box::new(error))
141 }
142}
143
144async fn central_events(
145 event: BluetoothEvent,
146 session: BluetoothSession,
147 adapter_id: AdapterId,
148) -> Option<Vec<CentralEvent>> {
149 match event {
150 BluetoothEvent::Device {
151 id,
152 event: device_event,
153 } if id.adapter() == adapter_id => match device_event {
154 DeviceEvent::Discovered => {
155 let device = session.get_device_info(&id).await.ok()?;
156 let peripheral_id: PeripheralId = device.id.into();
157 let mut events = vec![CentralEvent::DeviceDiscovered(peripheral_id.clone())];
158 if !device.services.is_empty() {
163 events.push(CentralEvent::ServicesAdvertisement {
164 id: peripheral_id,
165 services: device.services,
166 });
167 }
168 Some(events)
169 }
170 DeviceEvent::Connected { connected } => {
171 if connected {
172 Some(vec![CentralEvent::DeviceConnected(id.into())])
173 } else {
174 Some(vec![CentralEvent::DeviceDisconnected(id.into())])
175 }
176 }
177 DeviceEvent::Rssi { rssi } => {
178 let device = session.get_device_info(&id).await.ok()?;
179 Some(vec![CentralEvent::RssiUpdate {
180 id: device.id.into(),
181 rssi,
182 }])
183 }
184 DeviceEvent::ManufacturerData { manufacturer_data } => {
185 let device = session.get_device_info(&id).await.ok()?;
186 Some(vec![CentralEvent::ManufacturerDataAdvertisement {
187 id: device.id.into(),
188 manufacturer_data,
189 }])
190 }
191 DeviceEvent::ServiceData { service_data } => {
192 let device = session.get_device_info(&id).await.ok()?;
193 Some(vec![CentralEvent::ServiceDataAdvertisement {
194 id: device.id.into(),
195 service_data,
196 }])
197 }
198 DeviceEvent::Services { services } => {
199 let device = session.get_device_info(&id).await.ok()?;
200 Some(vec![CentralEvent::ServicesAdvertisement {
201 id: device.id.into(),
202 services,
203 }])
204 }
205 _ => None,
206 },
207 BluetoothEvent::Adapter {
208 id,
209 event: adapter_event,
210 } if id == adapter_id => match adapter_event {
211 AdapterEvent::Powered { powered } => {
212 let state = get_central_state(powered);
213 Some(vec![CentralEvent::StateUpdate(state)])
214 }
215 _ => None,
216 },
217 _ => None,
218 }
219}