1 use bt_topshim::btif;
2 use bt_topshim::btif::{ffi, BluetoothCallbacks, BluetoothInterface};
3 use bt_topshim::topstack;
4 use num_traits::{FromPrimitive, ToPrimitive};
5 use std::convert::TryFrom;
6 use std::env;
7 use std::sync::Arc;
8 use std::time::Duration;
9 use tokio::sync::mpsc;
10 use tokio::sync::mpsc::{Receiver, Sender};
11 use tokio::time::sleep;
12 
13 // DO NOT REMOVE
14 // Required so that bt_shim is linked into the final image
15 extern crate bt_shim;
16 
17 enum Callbacks {
18     AdapterStateChanged(btif::BtState),
19     AdapterPropertiesChanged(i32, i32, Vec<ffi::BtProperty>),
20     RemoteDevicePropertiesChanged(i32, ffi::RustRawAddress, i32, Vec<ffi::BtProperty>),
21     DeviceFound(i32, Vec<ffi::BtProperty>),
22     DiscoveryStateChanged(btif::BtDiscoveryState),
23 }
24 struct Context {
25     tx: Sender<Callbacks>,
26     rx: Receiver<Callbacks>,
27     callbacks: Arc<BluetoothCallbacks>,
28     intf: BluetoothInterface,
29 }
30 
make_context(intf: BluetoothInterface) -> Context31 fn make_context(intf: BluetoothInterface) -> Context {
32     let (tx, rx) = mpsc::channel::<Callbacks>(1);
33 
34     let (tx1, tx2, tx3, tx4, tx5) = (tx.clone(), tx.clone(), tx.clone(), tx.clone(), tx.clone());
35     let cb = Arc::new(BluetoothCallbacks {
36         adapter_state_changed: Box::new(move |state| {
37             let txl = tx1.clone();
38             topstack::get_runtime().spawn(async move {
39                 txl.send(Callbacks::AdapterStateChanged(state)).await;
40             });
41         }),
42         adapter_properties_changed: Box::new(move |status, count, props| {
43             let txl = tx2.clone();
44             topstack::get_runtime().spawn(async move {
45                 txl.send(Callbacks::AdapterPropertiesChanged(status, count, props)).await;
46             });
47         }),
48         remote_device_properties_changed: Box::new(move |status, address, count, props| {
49             let txl = tx5.clone();
50             topstack::get_runtime().spawn(async move {
51                 txl.send(Callbacks::RemoteDevicePropertiesChanged(status, address, count, props));
52             });
53         }),
54         device_found: Box::new(move |count, props| {
55             let txl = tx3.clone();
56             topstack::get_runtime().spawn(async move {
57                 txl.send(Callbacks::DeviceFound(count, props)).await;
58             });
59         }),
60         discovery_state_changed: Box::new(move |state| {
61             let txl = tx4.clone();
62             topstack::get_runtime().spawn(async move {
63                 txl.send(Callbacks::DiscoveryStateChanged(state)).await;
64             });
65         }),
66         pin_request: Box::new(move |_address, _bdname, _cod, _min_16_digit| {
67             println!("Pin request callback");
68         }),
69         ssp_request: Box::new(move |_address, _bdname, _cod, _variant, _passkey| {
70             println!("Ssp request callback");
71         }),
72         bond_state_changed: Box::new(move |_status, _address, _state| {
73             println!("Bond state changed");
74         }),
75         acl_state_changed: Box::new(move |_status, _address, _state, _hci_reason| {
76             println!("Acl state changed");
77         }),
78     });
79 
80     return Context { tx, rx, callbacks: cb, intf };
81 }
82 
mainloop(context: &mut Context)83 async fn mainloop(context: &mut Context) {
84     'main: while let Some(cb) = context.rx.recv().await {
85         match cb {
86             Callbacks::AdapterStateChanged(state) => {
87                 println!("Adapter state changed to {}", state.to_i32().unwrap());
88 
89                 if state == btif::BtState::On {
90                     context.intf.get_adapter_properties();
91                 }
92             }
93             Callbacks::AdapterPropertiesChanged(status, _count, properties) => {
94                 if status != 0 {
95                     println!("Failed property change: {}", status);
96                 }
97 
98                 for p in properties {
99                     let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
100                         Some(x) => x,
101                         None => btif::BtPropertyType::Unknown,
102                     };
103                     println!("Property {:?} is ({:?})", proptype, p.val);
104                 }
105 
106                 // Scan for 5s and then cancel
107                 println!("Starting discovery");
108                 context.intf.start_discovery();
109             }
110             Callbacks::RemoteDevicePropertiesChanged(status, address, _count, properties) => {
111                 if status != 0 {
112                     println!("Failed remote property change: {}", status);
113                 }
114 
115                 println!("Properties for {:?}", address.address);
116 
117                 for p in properties {
118                     let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
119                         Some(x) => x,
120                         None => btif::BtPropertyType::Unknown,
121                     };
122                     println!("Property {:?} is ({:?})", proptype, p.val);
123                 }
124             }
125             Callbacks::DeviceFound(_count, properties) => {
126                 print!("Device found: ");
127 
128                 for p in properties {
129                     let proptype = match btif::BtPropertyType::from_i32(p.prop_type) {
130                         Some(x) => x,
131                         None => btif::BtPropertyType::Unknown,
132                     };
133 
134                     if proptype == btif::BtPropertyType::BdAddr {
135                         print!(" Addr[{:?}]", p.val);
136                     } else if proptype == btif::BtPropertyType::BdName {
137                         print!(
138                             " Name[{:?}]",
139                             p.val.iter().map(|u| char::try_from(*u).unwrap()).collect::<String>()
140                         );
141                     }
142                 }
143 
144                 println!("");
145             }
146             Callbacks::DiscoveryStateChanged(state) => {
147                 if state == btif::BtDiscoveryState::Started {
148                     sleep(Duration::from_millis(5000)).await;
149                     context.intf.cancel_discovery();
150 
151                     break 'main;
152                 }
153             }
154         }
155     }
156 }
157 
main()158 fn main() {
159     println!("Bluetooth Adapter Daemon");
160 
161     // Drop the first arg (which is the binary name)
162     let all_args: Vec<String> = env::args().collect();
163     let args = all_args[1..].to_vec();
164 
165     let intf = BluetoothInterface::new();
166     let mut context = make_context(intf);
167 
168     topstack::get_runtime().block_on(async move {
169         if !context.intf.initialize(context.callbacks.clone(), args) {
170             panic!("Couldn't initialize bluetooth interface!");
171         }
172 
173         println!("Enabling...");
174         context.intf.enable();
175 
176         println!("Running mainloop now");
177         mainloop(&mut context).await;
178 
179         println!("Disabling and exiting...");
180         context.intf.disable();
181     });
182 }
183