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 mut events = vec![CentralEvent::DeviceDiscovered(device.id.clone().into())];
51 if device.connected {
52 events.push(CentralEvent::DeviceConnected(device.id.into()));
53 }
54 events.into_iter()
55 }),
56 );
57
58 let session = self.session.clone();
59 let adapter_id = self.adapter.clone();
60 let events = events
61 .filter_map(move |event| central_event(event, session.clone(), adapter_id.clone()));
62
63 Ok(Box::pin(initial_events.chain(events)))
64 }
65
66 async fn start_scan(&self, filter: ScanFilter) -> Result<()> {
67 let filter = DiscoveryFilter {
68 service_uuids: filter.services,
69 duplicate_data: Some(true),
70 transport: Some(Transport::Auto),
71 ..Default::default()
72 };
73 self.session
74 .start_discovery_on_adapter_with_filter(&self.adapter, &filter)
75 .await?;
76 Ok(())
77 }
78
79 async fn stop_scan(&self) -> Result<()> {
80 self.session
81 .stop_discovery_on_adapter(&self.adapter)
82 .await?;
83 Ok(())
84 }
85
86 async fn peripherals(&self) -> Result<Vec<Peripheral>> {
87 let devices = self.session.get_devices_on_adapter(&self.adapter).await?;
88 Ok(devices
89 .into_iter()
90 .map(|device| Peripheral::new(self.session.clone(), device))
91 .collect())
92 }
93
94 async fn peripheral(&self, id: &PeripheralId) -> Result<Peripheral> {
95 let device = self.session.get_device_info(&id.0).await.map_err(|e| {
96 if let BluetoothError::DbusError(_) = e {
97 Error::DeviceNotFound
98 } else {
99 e.into()
100 }
101 })?;
102 Ok(Peripheral::new(self.session.clone(), device))
103 }
104
105 async fn add_peripheral(&self, _address: &PeripheralId) -> Result<Peripheral> {
106 Err(Error::NotSupported(
107 "Can't add a Peripheral from a PeripheralId".to_string(),
108 ))
109 }
110
111 async fn adapter_info(&self) -> Result<String> {
112 let adapter_info = self.session.get_adapter_info(&self.adapter).await?;
113 Ok(format!("{} ({})", adapter_info.id, adapter_info.modalias))
114 }
115
116 async fn adapter_state(&self) -> Result<CentralState> {
117 let mut powered = false;
118 if let Ok(info) = self.session.get_adapter_info(&self.adapter).await {
119 powered = info.powered;
120 }
121 Ok(get_central_state(powered))
122 }
123}
124
125impl From<BluetoothError> for Error {
126 fn from(error: BluetoothError) -> Self {
127 Error::Other(Box::new(error))
128 }
129}
130
131async fn central_event(
132 event: BluetoothEvent,
133 session: BluetoothSession,
134 adapter_id: AdapterId,
135) -> Option<CentralEvent> {
136 match event {
137 BluetoothEvent::Device {
138 id,
139 event: device_event,
140 } if id.adapter() == adapter_id => match device_event {
141 DeviceEvent::Discovered => {
142 let device = session.get_device_info(&id).await.ok()?;
143 Some(CentralEvent::DeviceDiscovered(device.id.into()))
144 }
145 DeviceEvent::Connected { connected } => {
146 let device = session.get_device_info(&id).await.ok()?;
147 if connected {
148 Some(CentralEvent::DeviceConnected(device.id.into()))
149 } else {
150 Some(CentralEvent::DeviceDisconnected(device.id.into()))
151 }
152 }
153 DeviceEvent::Rssi { rssi: _ } => {
154 let device = session.get_device_info(&id).await.ok()?;
155 Some(CentralEvent::DeviceUpdated(device.id.into()))
156 }
157 DeviceEvent::ManufacturerData { manufacturer_data } => {
158 let device = session.get_device_info(&id).await.ok()?;
159 Some(CentralEvent::ManufacturerDataAdvertisement {
160 id: device.id.into(),
161 manufacturer_data,
162 })
163 }
164 DeviceEvent::ServiceData { service_data } => {
165 let device = session.get_device_info(&id).await.ok()?;
166 Some(CentralEvent::ServiceDataAdvertisement {
167 id: device.id.into(),
168 service_data,
169 })
170 }
171 DeviceEvent::Services { services } => {
172 let device = session.get_device_info(&id).await.ok()?;
173 Some(CentralEvent::ServicesAdvertisement {
174 id: device.id.into(),
175 services,
176 })
177 }
178 _ => None,
179 },
180 BluetoothEvent::Adapter {
181 id,
182 event: adapter_event,
183 } if id == adapter_id => match adapter_event {
184 AdapterEvent::Powered { powered } => {
185 let state = get_central_state(powered);
186 Some(CentralEvent::StateUpdate(state))
187 }
188 _ => None,
189 },
190 _ => None,
191 }
192}