Skip to main content

bluetooth_rust/
linux.rs

1//! Linux specific bluetooth code
2
3use std::collections::{HashMap, HashSet};
4use std::marker::PhantomData;
5
6use bluer::{AdapterEvent, DeviceProperty};
7use futures::FutureExt;
8use futures::StreamExt;
9
10impl super::BluetoothRfcommConnectableAsyncTrait for bluer::rfcomm::ConnectRequest {
11    async fn accept(self) -> Result<crate::BluetoothStream, String> {
12        bluer::rfcomm::ConnectRequest::accept(self)
13            .map(|a| crate::BluetoothStream::Bluez(Box::pin(a)))
14            .map_err(|e| e.to_string())
15    }
16}
17
18impl super::BluetoothRfcommProfileAsyncTrait for bluer::rfcomm::ProfileHandle {
19    async fn connectable(&mut self) -> Result<crate::BluetoothRfcommConnectableAsync, String> {
20        self.next()
21            .await
22            .map(|a| crate::BluetoothRfcommConnectableAsync::Bluez(a))
23            .ok_or("Failed to get bluetooth connection".to_string())
24    }
25}
26
27impl super::BluetoothDeviceTrait for bluer::Device {
28    fn run_sdp(&mut self) {
29        todo!()
30    }
31
32    #[doc = " Get all known uuids for this device"]
33    fn get_uuids(&mut self) -> Result<Vec<crate::BluetoothUuid>, std::io::Error> {
34        todo!()
35    }
36
37    #[doc = " Retrieve the device name"]
38    fn get_name(&self) -> Result<String, std::io::Error> {
39        todo!()
40    }
41
42    #[doc = " Retrieve the device address"]
43    fn get_address(&mut self) -> Result<String, std::io::Error> {
44        todo!()
45    }
46
47    #[doc = " Retrieve the device pairing (bonding) status"]
48    fn get_pair_state(&self) -> Result<crate::PairingStatus, std::io::Error> {
49        todo!()
50    }
51
52    #[doc = " Attempt to get an rfcomm socket for the given uuid and seciruty setting"]
53    fn get_l2cap_socket(
54        &mut self,
55        uuid: crate::BluetoothUuid,
56        is_secure: bool,
57    ) -> Result<crate::BluetoothSocket, String> {
58        todo!()
59    }
60
61    #[doc = " Attempt to get an rfcomm socket for the given uuid and seciruty setting"]
62    fn get_rfcomm_socket(
63        &mut self,
64        uuid: crate::BluetoothUuid,
65        is_secure: bool,
66    ) -> Result<crate::BluetoothSocket, String> {
67        todo!()
68    }
69}
70
71/// An rfcomm socket with a bluetooth peer
72pub struct BluetoothRfcommSocket {
73    /// The rfcomm socket data, TODO
74    inner: u32,
75}
76
77/// A struct for managing discovery of bluetooth devices
78pub struct BluetoothDiscovery {}
79
80impl BluetoothDiscovery {
81    /// construct a new self
82    fn new() -> Self {
83        Self {}
84    }
85}
86
87impl super::BluetoothDiscoveryTrait for BluetoothDiscovery {}
88
89impl Drop for BluetoothDiscovery {
90    fn drop(&mut self) {}
91}
92
93/// The general bluetooth handler for the library. There should be only one per application on linux.
94pub struct BluetoothHandler {
95    /// The current bluetooth session
96    session: bluer::Session,
97    /// The list of bluetooth adapters for the system
98    adapters: Vec<bluer::Adapter>,
99    /// The agent for the handler
100    _blue_agent_handle: bluer::agent::AgentHandle,
101}
102
103impl TryFrom<super::BluetoothRfcommProfileSettings> for bluer::rfcomm::Profile {
104    type Error = String;
105    fn try_from(value: super::BluetoothRfcommProfileSettings) -> Result<Self, Self::Error> {
106        let service = if let Some(v) = value.service_uuid {
107            Some(bluer::Uuid::parse_str(&v).map_err(|e| e.to_string())?)
108        } else {
109            None
110        };
111        Ok(Self {
112            uuid: bluer::Uuid::parse_str(&value.uuid).map_err(|e| e.to_string())?,
113            name: value.name,
114            service,
115            role: None,
116            channel: value.channel,
117            psm: value.psm,
118            require_authentication: value.authenticate,
119            require_authorization: value.authorize,
120            auto_connect: value.auto_connect,
121            service_record: value.sdp_record,
122            version: value.sdp_version,
123            features: value.sdp_features,
124            ..Default::default()
125        })
126    }
127}
128
129impl super::BluetoothAdapterTrait for BluetoothHandler {
130    fn supports_async(&mut self) -> Option<&mut dyn super::AsyncBluetoothAdapterTrait> {
131        Some(self)
132    }
133
134    fn supports_sync(&mut self) -> Option<&mut dyn super::SyncBluetoothAdapterTrait> {
135        None
136    }
137}
138
139#[async_trait::async_trait]
140impl super::AsyncBluetoothAdapterTrait for BluetoothHandler {
141    async fn register_l2cap_profile(
142        &self,
143        settings: super::BluetoothL2capProfileSettings,
144    ) -> Result<crate::BluetoothL2capProfileAsync, String> {
145        todo!()
146    }
147
148    async fn register_rfcomm_profile(
149        &self,
150        settings: super::BluetoothRfcommProfileSettings,
151    ) -> Result<crate::BluetoothRfcommProfileAsync, String> {
152        self.session
153            .register_profile(settings.try_into()?)
154            .await
155            .map(|a| super::BluetoothRfcommProfileAsync::Bluez(a.into()))
156            .map_err(|e| e.to_string())
157    }
158
159    fn start_discovery(&self) -> crate::BluetoothDiscovery {
160        BluetoothDiscovery::new().into()
161    }
162
163    fn get_paired_devices(&self) -> Option<Vec<crate::BluetoothDevice>> {
164        let list = Vec::new();
165        for adapter in &self.adapters {
166            todo!();
167        }
168        Some(list)
169    }
170
171    async fn addresses(&self) -> Vec<super::BluetoothAdapterAddress> {
172        let mut a = Vec::new();
173        for adapter in &self.adapters {
174            if let Ok(adr) = adapter.address().await {
175                a.push(super::BluetoothAdapterAddress::Byte(adr.0));
176            }
177        }
178        a
179    }
180
181    async fn set_discoverable(&self, d: bool) -> Result<(), ()> {
182        for adapter in &self.adapters {
183            adapter.set_discoverable(d).await.map_err(|_| ())?;
184        }
185        Ok(())
186    }
187}
188
189impl BluetoothHandler {
190    /// Retrieve the bluetooth addresses for all bluetooth adapters present
191    pub async fn addresses(&self) -> Vec<bluer::Address> {
192        let mut addrs = Vec::new();
193        for a in &self.adapters {
194            if let Ok(addr) = a.address().await {
195                addrs.push(addr);
196            }
197        }
198        addrs
199    }
200
201    /// Construct a new self
202    pub async fn new(
203        s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
204    ) -> Result<Self, String> {
205        let session = bluer::Session::new().await.map_err(|e| e.to_string())?;
206
207        let adapter_names = session.adapter_names().await.map_err(|e| e.to_string())?;
208        let adapters: Vec<bluer::Adapter> = adapter_names
209            .iter()
210            .filter_map(|n| session.adapter(n).ok())
211            .collect();
212
213        let blue_agent = Self::build_agent(s);
214        let blue_agent_handle = session.register_agent(blue_agent).await;
215        println!("Registered a bluetooth agent {}", blue_agent_handle.is_ok());
216        Ok(Self {
217            session,
218            adapters,
219            _blue_agent_handle: blue_agent_handle.map_err(|e| e.to_string())?,
220        })
221    }
222
223    /// Enable all bluetooth adapters
224    async fn enable(&mut self) {
225        for adapter in &self.adapters {
226            adapter.set_powered(true).await.unwrap();
227            adapter.set_pairable(true).await.unwrap();
228        }
229    }
230
231    /// Disable all bluetooth adapters
232    async fn disable(&mut self) {
233        self.set_discoverable(false).await;
234        for adapter in &self.adapters {
235            adapter.set_powered(false).await.unwrap();
236            adapter.set_pairable(false).await.unwrap();
237        }
238    }
239
240    /// Enable or disable the discoverable of all bluetooth adapters
241    pub async fn set_discoverable(&mut self, d: bool) {
242        for adapter in &self.adapters {
243            adapter.set_discoverable(d).await.unwrap();
244        }
245    }
246
247    /// Register a profile with the bluetooth session
248    pub async fn register_rfcomm_profile(
249        &mut self,
250        profile: bluer::rfcomm::Profile,
251    ) -> Result<bluer::rfcomm::ProfileHandle, bluer::Error> {
252        self.session.register_profile(profile).await
253    }
254
255    /// Build a bluetooth agent for the handler
256    fn build_agent(
257        s: tokio::sync::mpsc::Sender<super::MessageToBluetoothHost>,
258    ) -> bluer::agent::Agent {
259        let mut blue_agent = bluer::agent::Agent::default();
260        blue_agent.request_default = true;
261        blue_agent.request_pin_code = None;
262        blue_agent.request_passkey = None;
263        let s2 = s.clone();
264        blue_agent.display_passkey = Some(Box::new(move |mut a| {
265            println!("Running process for display_passkey: {:?}", a);
266            let s3 = s2.clone();
267            async move {
268                let mut chan = tokio::sync::mpsc::channel(5);
269                let _ = s3.send(super::MessageToBluetoothHost::DisplayPasskey(a.passkey, chan.0)).await;
270                loop {
271                    let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
272                    tokio::select! {
273                        asdf = f => {
274                            match asdf {
275                                Ok(Some(m)) => {
276                                    match m {
277                                        super::ResponseToPasskey::Yes => {
278                                            let _ = s3.send(super::MessageToBluetoothHost::CancelDisplayPasskey).await;
279                                            return Ok(());
280                                        }
281                                        super::ResponseToPasskey::No => {
282                                            let _ = s3.send(super::MessageToBluetoothHost::CancelDisplayPasskey).await;
283                                            return Err(bluer::agent::ReqError::Rejected);
284                                        }
285                                        super::ResponseToPasskey::Cancel => {
286                                            let _ = s3.send(super::MessageToBluetoothHost::CancelDisplayPasskey).await;
287                                            return Err(bluer::agent::ReqError::Canceled);
288                                        }
289                                        super::ResponseToPasskey::Waiting => {}
290                                    }
291                                }
292                                Ok(None) => {}
293                                _ => {
294                                    let _ = s3.send(super::MessageToBluetoothHost::CancelDisplayPasskey).await;
295                                    return Err(bluer::agent::ReqError::Canceled);
296                                }
297                            }
298                        }
299                        _ = &mut a.cancel => {
300                            let _ = s3.send(super::MessageToBluetoothHost::CancelDisplayPasskey).await;
301                            break Err(bluer::agent::ReqError::Canceled);
302                        }
303                    }
304                }
305            }
306            .boxed()
307        }));
308        blue_agent.display_pin_code = Some(Box::new(|a| {
309            async move {
310                println!("Need to display pin code {:?}", a);
311                a.cancel.await.unwrap();
312                Ok(())
313            }
314            .boxed()
315        }));
316        let s2 = s.clone();
317        blue_agent.request_confirmation = Some(Box::new(move |a| {
318            println!("Need to confirm {:?}", a);
319            let s3 = s2.clone();
320            async move {
321                let mut chan = tokio::sync::mpsc::channel(5);
322                let _ = s3
323                    .send(super::MessageToBluetoothHost::ConfirmPasskey(
324                        a.passkey, chan.0,
325                    ))
326                    .await;
327                loop {
328                    let f = tokio::time::timeout(std::time::Duration::from_secs(5), chan.1.recv());
329                    let asdf = f.await;
330                    match asdf {
331                        Ok(Some(m)) => match m {
332                            super::ResponseToPasskey::Yes => {
333                                let _ = s3
334                                    .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
335                                    .await;
336                                return Ok(());
337                            }
338                            super::ResponseToPasskey::No => {
339                                let _ = s3
340                                    .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
341                                    .await;
342                                return Err(bluer::agent::ReqError::Rejected);
343                            }
344                            super::ResponseToPasskey::Cancel => {
345                                let _ = s3
346                                    .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
347                                    .await;
348                                return Err(bluer::agent::ReqError::Canceled);
349                            }
350                            super::ResponseToPasskey::Waiting => {}
351                        },
352                        Ok(None) => {}
353                        _ => {
354                            let _ = s3
355                                .send(super::MessageToBluetoothHost::CancelDisplayPasskey)
356                                .await;
357                            return Err(bluer::agent::ReqError::Canceled);
358                        }
359                    }
360                }
361            }
362            .boxed()
363        }));
364        blue_agent.request_authorization = Some(Box::new(|a| {
365            async move {
366                println!("Need to authorize {:?}", a);
367                Ok(())
368            }
369            .boxed()
370        }));
371        blue_agent.authorize_service = Some(Box::new(|a| {
372            async move {
373                println!("Need to authorize service {:?}", a);
374                Ok(())
375            }
376            .boxed()
377        }));
378        blue_agent
379    }
380
381    /// Issues the specified bluetooth command, with an optional response for the command
382    pub async fn issue_command(
383        &mut self,
384        cmd: super::BluetoothCommand,
385    ) -> Option<super::BluetoothResponse> {
386        match cmd {
387            super::BluetoothCommand::QueryNumAdapters => {
388                Some(super::BluetoothResponse::Adapters(0))
389            }
390            _ => None,
391        }
392    }
393
394    /// run a scan on all the bluetooth adapters
395    pub async fn scan<'a>(
396        &'a mut self,
397        bluetooth_devices: &mut HashMap<
398            bluer::Address,
399            (&'a bluer::Adapter, Option<bluer::Device>),
400        >,
401    ) {
402        let mut adapter_scanner = Vec::new();
403        for a in &self.adapters {
404            let da = a.discover_devices_with_changes().await.unwrap();
405            adapter_scanner.push((a, da));
406        }
407
408        for (adapt, da) in &mut adapter_scanner {
409            if let Some(e) = da.next().await {
410                match e {
411                    AdapterEvent::DeviceAdded(addr) => {
412                        println!("Device added {:?}", addr);
413                        bluetooth_devices.insert(addr, (adapt, None));
414                    }
415                    AdapterEvent::DeviceRemoved(addr) => {
416                        println!("Device removed {:?}", addr);
417                        bluetooth_devices.remove_entry(&addr);
418                    }
419                    AdapterEvent::PropertyChanged(prop) => {
420                        println!("Property changed {:?}", prop);
421                    }
422                }
423            }
424        }
425        for (addr, (adapter, dev)) in bluetooth_devices {
426            if dev.is_none() {
427                if let Ok(d) = adapter.device(*addr) {
428                    if let Ok(ps) = d.all_properties().await {
429                        for p in ps {}
430                    }
431                    *dev = Some(d);
432                }
433            }
434        }
435    }
436}