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