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