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