1 //! Shim for `bt_interface_t`, providing access to libbluetooth.
2 //!
3 //! This is a shim interface for calling the C++ bluetooth interface via Rust.
4
5 use crate::bindings::root as bindings;
6 use crate::topstack::get_dispatchers;
7 use num_traits::cast::{FromPrimitive, ToPrimitive};
8 use std::cmp;
9 use std::fmt::{Debug, Formatter, Result};
10 use std::mem;
11 use std::os::raw::c_char;
12 use std::sync::{Arc, Mutex};
13 use std::vec::Vec;
14 use topshim_macros::cb_variant;
15
16 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
17 #[repr(u32)]
18 pub enum BtState {
19 Off = 0,
20 On,
21 }
22
23 impl From<bindings::bt_state_t> for BtState {
from(item: bindings::bt_state_t) -> Self24 fn from(item: bindings::bt_state_t) -> Self {
25 BtState::from_u32(item).unwrap_or_else(|| BtState::Off)
26 }
27 }
28
29 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
30 #[repr(u32)]
31 pub enum BtTransport {
32 Auto = 0,
33 Bredr,
34 Le,
35 }
36
37 impl From<i32> for BtTransport {
from(item: i32) -> Self38 fn from(item: i32) -> Self {
39 BtTransport::from_i32(item).unwrap_or_else(|| BtTransport::Auto)
40 }
41 }
42
43 impl From<BtTransport> for i32 {
from(item: BtTransport) -> Self44 fn from(item: BtTransport) -> Self {
45 item.to_i32().unwrap_or_else(|| 0)
46 }
47 }
48
49 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
50 #[repr(u32)]
51 pub enum BtSspVariant {
52 PasskeyConfirmation = 0,
53 PasskeyEntry,
54 Consent,
55 PasskeyNotification,
56 }
57
58 impl From<bindings::bt_ssp_variant_t> for BtSspVariant {
from(item: bindings::bt_ssp_variant_t) -> Self59 fn from(item: bindings::bt_ssp_variant_t) -> Self {
60 BtSspVariant::from_u32(item).unwrap_or_else(|| BtSspVariant::PasskeyConfirmation)
61 }
62 }
63
64 impl From<BtSspVariant> for bindings::bt_ssp_variant_t {
from(item: BtSspVariant) -> Self65 fn from(item: BtSspVariant) -> Self {
66 item.to_u32().unwrap_or_else(|| 0)
67 }
68 }
69
70 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
71 #[repr(u32)]
72 pub enum BtBondState {
73 NotBonded = 0,
74 Bonding,
75 Bonded,
76 }
77
78 impl From<bindings::bt_bond_state_t> for BtBondState {
from(item: bindings::bt_bond_state_t) -> Self79 fn from(item: bindings::bt_bond_state_t) -> Self {
80 BtBondState::from_u32(item).unwrap_or_else(|| BtBondState::NotBonded)
81 }
82 }
83
84 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
85 #[repr(u32)]
86 pub enum BtConnectionState {
87 NotConnected = 0,
88 ConnectedOnly = 1,
89 EncryptedBredr = 3,
90 EncryptedLe = 5,
91 }
92
93 impl From<i32> for BtConnectionState {
from(item: i32) -> Self94 fn from(item: i32) -> Self {
95 let fallback = if item > 0 {
96 BtConnectionState::ConnectedOnly
97 } else {
98 BtConnectionState::NotConnected
99 };
100
101 BtConnectionState::from_i32(item).unwrap_or(fallback)
102 }
103 }
104
105 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
106 #[repr(u32)]
107 pub enum BtAclState {
108 Connected = 0,
109 Disconnected,
110 }
111
112 impl From<bindings::bt_acl_state_t> for BtAclState {
from(item: bindings::bt_acl_state_t) -> Self113 fn from(item: bindings::bt_acl_state_t) -> Self {
114 BtAclState::from_u32(item).unwrap_or_else(|| BtAclState::Disconnected)
115 }
116 }
117
118 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
119 #[repr(u32)]
120 pub enum BtDeviceType {
121 Bredr,
122 Ble,
123 Dual,
124 Unknown,
125 }
126
127 #[derive(Clone, Debug, Eq, Hash, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
128 #[repr(u32)]
129 pub enum BtPropertyType {
130 BdName = 0x1,
131 BdAddr,
132 Uuids,
133 ClassOfDevice,
134 TypeOfDevice,
135 ServiceRecord,
136 AdapterScanMode,
137 AdapterBondedDevices,
138 AdapterDiscoverableTimeout,
139 RemoteFriendlyName,
140 RemoteRssi,
141 RemoteVersionInfo,
142 LocalLeFeatures,
143 LocalIoCaps,
144 LocalIoCapsBle,
145 DynamicAudioBuffer,
146
147 Unknown = 0xFE,
148 RemoteDeviceTimestamp = 0xFF,
149 }
150
151 impl From<u32> for BtPropertyType {
from(item: u32) -> Self152 fn from(item: u32) -> Self {
153 BtPropertyType::from_u32(item).unwrap_or_else(|| BtPropertyType::Unknown)
154 }
155 }
156
157 impl From<BtPropertyType> for u32 {
from(item: BtPropertyType) -> Self158 fn from(item: BtPropertyType) -> Self {
159 item.to_u32().unwrap_or_else(|| 0)
160 }
161 }
162
163 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
164 #[repr(u32)]
165 pub enum BtDiscoveryState {
166 Stopped = 0x0,
167 Started,
168 }
169
170 impl From<u32> for BtDiscoveryState {
from(item: u32) -> Self171 fn from(item: u32) -> Self {
172 BtDiscoveryState::from_u32(item).unwrap_or_else(|| BtDiscoveryState::Stopped)
173 }
174 }
175
176 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
177 #[repr(u32)]
178 pub enum BtStatus {
179 Success = 0,
180 Fail,
181 NotReady,
182 NoMemory,
183 Busy,
184 Done,
185 Unsupported,
186 InvalidParam,
187 Unhandled,
188 AuthFailure,
189 RemoteDeviceDown,
190 AuthRejected,
191 JniEnvironmentError,
192 JniThreadAttachError,
193 WakeLockError,
194
195 // Any statuses that couldn't be cleanly converted
196 Unknown = 0xff,
197 }
198
ascii_to_string(data: &[u8], length: usize) -> String199 pub fn ascii_to_string(data: &[u8], length: usize) -> String {
200 // We need to reslice data because from_utf8 tries to interpret the
201 // whole slice and not just what is before the null terminated portion
202 let ascii = data
203 .iter()
204 .enumerate()
205 .take_while(|&(pos, &c)| c != 0 && pos < length)
206 .map(|(_pos, &x)| x.clone())
207 .collect::<Vec<u8>>();
208
209 return String::from_utf8(ascii).unwrap_or_default();
210 }
211
u32_from_bytes(item: &[u8]) -> u32212 fn u32_from_bytes(item: &[u8]) -> u32 {
213 let mut u: [u8; 4] = [0; 4];
214 let len = std::cmp::min(item.len(), 4);
215 u[0..len].copy_from_slice(&item);
216 u32::from_ne_bytes(u)
217 }
218
219 impl From<bindings::bt_status_t> for BtStatus {
from(item: bindings::bt_status_t) -> Self220 fn from(item: bindings::bt_status_t) -> Self {
221 match BtStatus::from_u32(item) {
222 Some(x) => x,
223 _ => BtStatus::Unknown,
224 }
225 }
226 }
227
228 impl From<bindings::bt_bdname_t> for String {
from(item: bindings::bt_bdname_t) -> Self229 fn from(item: bindings::bt_bdname_t) -> Self {
230 ascii_to_string(&item.name, item.name.len())
231 }
232 }
233
234 #[derive(Debug, Clone)]
235 pub struct BtServiceRecord {
236 pub uuid: bindings::bluetooth::Uuid,
237 pub channel: u16,
238 pub name: String,
239 }
240
241 impl From<bindings::bt_service_record_t> for BtServiceRecord {
from(item: bindings::bt_service_record_t) -> Self242 fn from(item: bindings::bt_service_record_t) -> Self {
243 let name = item.name.iter().map(|&x| x.clone() as u8).collect::<Vec<u8>>();
244
245 BtServiceRecord {
246 uuid: item.uuid,
247 channel: item.channel,
248 name: ascii_to_string(name.as_slice(), name.len()),
249 }
250 }
251 }
252
253 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
254 #[repr(u32)]
255 pub enum BtScanMode {
256 None_,
257 Connectable,
258 ConnectableDiscoverable,
259 }
260
261 impl From<bindings::bt_scan_mode_t> for BtScanMode {
from(item: bindings::bt_scan_mode_t) -> Self262 fn from(item: bindings::bt_scan_mode_t) -> Self {
263 BtScanMode::from_u32(item).unwrap_or(BtScanMode::None_)
264 }
265 }
266
267 #[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
268 #[repr(u32)]
269 pub enum BtIoCap {
270 Out,
271 InOut,
272 In,
273 None_,
274 KbDisp,
275 Max,
276 Unknown = 0xff,
277 }
278
279 impl From<bindings::bt_io_cap_t> for BtIoCap {
from(item: bindings::bt_io_cap_t) -> Self280 fn from(item: bindings::bt_io_cap_t) -> Self {
281 BtIoCap::from_u32(item).unwrap_or(BtIoCap::Unknown)
282 }
283 }
284
285 pub type BtHciErrorCode = u8;
286 pub type BtLocalLeFeatures = bindings::bt_local_le_features_t;
287 pub type BtPinCode = bindings::bt_pin_code_t;
288 pub type BtRemoteVersion = bindings::bt_remote_version_t;
289 pub type Uuid = bindings::bluetooth::Uuid;
290 pub type Uuid128Bit = bindings::bluetooth::Uuid_UUID128Bit;
291
292 /// All supported Bluetooth properties after conversion.
293 #[derive(Debug, Clone)]
294 pub enum BluetoothProperty {
295 BdName(String),
296 BdAddr(RawAddress),
297 Uuids(Vec<Uuid>),
298 ClassOfDevice(u32),
299 TypeOfDevice(BtDeviceType),
300 ServiceRecord(BtServiceRecord),
301 AdapterScanMode(BtScanMode),
302 AdapterBondedDevices(Vec<RawAddress>),
303 AdapterDiscoverableTimeout(u32),
304 RemoteFriendlyName(String),
305 RemoteRssi(i8),
306 RemoteVersionInfo(BtRemoteVersion),
307 LocalLeFeatures(BtLocalLeFeatures),
308 LocalIoCaps(BtIoCap),
309 LocalIoCapsBle(BtIoCap),
310 DynamicAudioBuffer(),
311 RemoteDeviceTimestamp(),
312
313 Unknown(),
314 }
315
316 /// Wherever names are sent in bindings::bt_property_t, the size of the character
317 /// arrays are 256. Keep one extra byte for null termination.
318 const PROPERTY_NAME_MAX: usize = 255;
319
320 impl BluetoothProperty {
get_type(&self) -> BtPropertyType321 pub fn get_type(&self) -> BtPropertyType {
322 match &*self {
323 BluetoothProperty::BdName(_) => BtPropertyType::BdName,
324 BluetoothProperty::BdAddr(_) => BtPropertyType::BdAddr,
325 BluetoothProperty::Uuids(_) => BtPropertyType::Uuids,
326 BluetoothProperty::ClassOfDevice(_) => BtPropertyType::ClassOfDevice,
327 BluetoothProperty::TypeOfDevice(_) => BtPropertyType::TypeOfDevice,
328 BluetoothProperty::ServiceRecord(_) => BtPropertyType::ServiceRecord,
329 BluetoothProperty::AdapterScanMode(_) => BtPropertyType::AdapterScanMode,
330 BluetoothProperty::AdapterBondedDevices(_) => BtPropertyType::AdapterBondedDevices,
331 BluetoothProperty::AdapterDiscoverableTimeout(_) => {
332 BtPropertyType::AdapterDiscoverableTimeout
333 }
334 BluetoothProperty::RemoteFriendlyName(_) => BtPropertyType::RemoteFriendlyName,
335 BluetoothProperty::RemoteRssi(_) => BtPropertyType::RemoteRssi,
336 BluetoothProperty::RemoteVersionInfo(_) => BtPropertyType::RemoteVersionInfo,
337 BluetoothProperty::LocalLeFeatures(_) => BtPropertyType::LocalLeFeatures,
338 BluetoothProperty::LocalIoCaps(_) => BtPropertyType::LocalIoCaps,
339 BluetoothProperty::LocalIoCapsBle(_) => BtPropertyType::LocalIoCapsBle,
340 BluetoothProperty::DynamicAudioBuffer() => BtPropertyType::DynamicAudioBuffer,
341 BluetoothProperty::RemoteDeviceTimestamp() => BtPropertyType::RemoteDeviceTimestamp,
342 BluetoothProperty::Unknown() => BtPropertyType::Unknown,
343 }
344 }
345
get_len(&self) -> usize346 fn get_len(&self) -> usize {
347 match &*self {
348 BluetoothProperty::BdName(name) => cmp::min(PROPERTY_NAME_MAX, name.len() + 1),
349 BluetoothProperty::BdAddr(addr) => addr.val.len(),
350 BluetoothProperty::Uuids(uulist) => uulist.len() * mem::size_of::<Uuid>(),
351 BluetoothProperty::ClassOfDevice(_) => mem::size_of::<u32>(),
352 BluetoothProperty::TypeOfDevice(_) => mem::size_of::<BtDeviceType>(),
353 BluetoothProperty::ServiceRecord(rec) => {
354 mem::size_of::<BtServiceRecord>() + cmp::min(PROPERTY_NAME_MAX, rec.name.len() + 1)
355 }
356 BluetoothProperty::AdapterScanMode(_) => mem::size_of::<BtScanMode>(),
357 BluetoothProperty::AdapterBondedDevices(devlist) => {
358 devlist.len() * mem::size_of::<RawAddress>()
359 }
360 BluetoothProperty::AdapterDiscoverableTimeout(_) => mem::size_of::<u32>(),
361 BluetoothProperty::RemoteFriendlyName(name) => {
362 cmp::min(PROPERTY_NAME_MAX, name.len() + 1)
363 }
364 BluetoothProperty::RemoteRssi(_) => mem::size_of::<i8>(),
365 BluetoothProperty::RemoteVersionInfo(_) => mem::size_of::<BtRemoteVersion>(),
366 BluetoothProperty::LocalLeFeatures(_) => mem::size_of::<BtLocalLeFeatures>(),
367 BluetoothProperty::LocalIoCaps(_) => mem::size_of::<BtIoCap>(),
368 BluetoothProperty::LocalIoCapsBle(_) => mem::size_of::<BtIoCap>(),
369
370 // TODO(abps) - Figure out sizes for these
371 BluetoothProperty::DynamicAudioBuffer() => 0,
372 BluetoothProperty::RemoteDeviceTimestamp() => 0,
373 BluetoothProperty::Unknown() => 0,
374 }
375 }
376
377 /// Given a mutable array, this will copy the data to that array and return a
378 /// pointer to it.
379 ///
380 /// The lifetime of the returned pointer is tied to that of the slice given.
get_data_ptr<'a>(&'a self, data: &'a mut [u8]) -> *mut u8381 fn get_data_ptr<'a>(&'a self, data: &'a mut [u8]) -> *mut u8 {
382 let len = self.get_len();
383 match &*self {
384 BluetoothProperty::BdName(name) => {
385 let copy_len = len - 1;
386 data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
387 data[copy_len] = 0;
388 }
389 BluetoothProperty::BdAddr(addr) => {
390 data.copy_from_slice(&addr.val);
391 }
392 BluetoothProperty::Uuids(uulist) => {
393 for (idx, &uuid) in uulist.iter().enumerate() {
394 let start = idx * mem::size_of::<Uuid>();
395 let end = start + mem::size_of::<Uuid>();
396 data[start..end].copy_from_slice(&uuid.uu);
397 }
398 }
399 BluetoothProperty::ClassOfDevice(cod) => {
400 data.copy_from_slice(&cod.to_ne_bytes());
401 }
402 BluetoothProperty::TypeOfDevice(tod) => {
403 data.copy_from_slice(&BtDeviceType::to_u32(tod).unwrap_or_default().to_ne_bytes());
404 }
405 BluetoothProperty::ServiceRecord(sr) => {
406 // Do an unsafe cast to binding:: type and assign the values
407 // The underlying memory location is provided by |data| which will
408 // have enough space because it uses get_len()
409 let mut record =
410 unsafe { &mut *(data.as_mut_ptr() as *mut bindings::bt_service_record_t) };
411 record.uuid = sr.uuid;
412 record.channel = sr.channel;
413 let name_len = len - mem::size_of::<BtServiceRecord>() - 1;
414 record.name[0..name_len].copy_from_slice(
415 &(sr.name.as_bytes().iter().map(|x| *x as c_char).collect::<Vec<c_char>>())
416 [0..name_len],
417 );
418 record.name[name_len] = 0;
419 }
420 BluetoothProperty::AdapterScanMode(sm) => {
421 data.copy_from_slice(&BtScanMode::to_u32(sm).unwrap_or_default().to_ne_bytes());
422 }
423 BluetoothProperty::AdapterBondedDevices(devlist) => {
424 for (idx, &dev) in devlist.iter().enumerate() {
425 let start = idx * mem::size_of::<RawAddress>();
426 let end = idx + mem::size_of::<RawAddress>();
427 data[start..end].copy_from_slice(&dev.val);
428 }
429 }
430 BluetoothProperty::AdapterDiscoverableTimeout(timeout) => {
431 data.copy_from_slice(&timeout.to_ne_bytes());
432 }
433 BluetoothProperty::RemoteFriendlyName(name) => {
434 let copy_len = len - 1;
435 data[0..copy_len].copy_from_slice(&name.as_bytes()[0..copy_len]);
436 data[copy_len] = 0;
437 }
438 BluetoothProperty::RemoteRssi(rssi) => {
439 data[0] = *rssi as u8;
440 }
441 BluetoothProperty::RemoteVersionInfo(rvi) => {
442 let ptr: *const BtRemoteVersion = rvi;
443 let slice = unsafe {
444 std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtRemoteVersion>())
445 };
446 data.copy_from_slice(&slice);
447 }
448 BluetoothProperty::LocalLeFeatures(llf) => {
449 let ptr: *const BtLocalLeFeatures = llf;
450 let slice = unsafe {
451 std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtLocalLeFeatures>())
452 };
453 data.copy_from_slice(&slice);
454 }
455 BluetoothProperty::LocalIoCaps(iocap) => {
456 data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
457 }
458 BluetoothProperty::LocalIoCapsBle(iocap) => {
459 data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
460 }
461 BluetoothProperty::DynamicAudioBuffer() => (),
462 BluetoothProperty::RemoteDeviceTimestamp() => (),
463 BluetoothProperty::Unknown() => (),
464 };
465
466 data.as_mut_ptr()
467 }
468 }
469
470 // TODO(abps) - Check that sizes are correct when given a BtProperty
471 impl From<bindings::bt_property_t> for BluetoothProperty {
from(prop: bindings::bt_property_t) -> Self472 fn from(prop: bindings::bt_property_t) -> Self {
473 let slice: &[u8] =
474 unsafe { std::slice::from_raw_parts(prop.val as *mut u8, prop.len as usize) };
475 let len = prop.len as usize;
476
477 match BtPropertyType::from(prop.type_) {
478 BtPropertyType::BdName => BluetoothProperty::BdName(ascii_to_string(slice, len)),
479 BtPropertyType::BdAddr => {
480 BluetoothProperty::BdAddr(RawAddress::from_bytes(slice).unwrap_or_default())
481 }
482 BtPropertyType::Uuids => {
483 let count = len / mem::size_of::<Uuid>();
484 BluetoothProperty::Uuids(ptr_to_vec(prop.val as *mut Uuid, count))
485 }
486 BtPropertyType::ClassOfDevice => {
487 BluetoothProperty::ClassOfDevice(u32_from_bytes(slice))
488 }
489 BtPropertyType::TypeOfDevice => BluetoothProperty::TypeOfDevice(
490 BtDeviceType::from_u32(u32_from_bytes(slice)).unwrap_or(BtDeviceType::Bredr),
491 ),
492 BtPropertyType::ServiceRecord => {
493 let v = unsafe { *(prop.val as *const bindings::bt_service_record_t) };
494 BluetoothProperty::ServiceRecord(BtServiceRecord::from(v))
495 }
496 BtPropertyType::AdapterScanMode => BluetoothProperty::AdapterScanMode(
497 BtScanMode::from_u32(u32_from_bytes(slice)).unwrap_or(BtScanMode::None_),
498 ),
499 BtPropertyType::AdapterBondedDevices => {
500 let count = len / mem::size_of::<RawAddress>();
501 BluetoothProperty::AdapterBondedDevices(ptr_to_vec(
502 prop.val as *mut RawAddress,
503 count,
504 ))
505 }
506 BtPropertyType::AdapterDiscoverableTimeout => {
507 BluetoothProperty::AdapterDiscoverableTimeout(u32_from_bytes(slice))
508 }
509 BtPropertyType::RemoteFriendlyName => {
510 BluetoothProperty::RemoteFriendlyName(ascii_to_string(slice, len))
511 }
512 BtPropertyType::RemoteRssi => BluetoothProperty::RemoteRssi(slice[0] as i8),
513 BtPropertyType::RemoteVersionInfo => {
514 let v = unsafe { *(prop.val as *const BtRemoteVersion) };
515 BluetoothProperty::RemoteVersionInfo(v.clone())
516 }
517 BtPropertyType::LocalLeFeatures => {
518 let v = unsafe { *(prop.val as *const BtLocalLeFeatures) };
519 BluetoothProperty::LocalLeFeatures(v.clone())
520 }
521 BtPropertyType::LocalIoCaps => BluetoothProperty::LocalIoCaps(
522 BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
523 ),
524 BtPropertyType::LocalIoCapsBle => BluetoothProperty::LocalIoCapsBle(
525 BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
526 ),
527
528 // TODO(abps) - Figure out if these values should actually have contents
529 BtPropertyType::DynamicAudioBuffer => BluetoothProperty::DynamicAudioBuffer(),
530 BtPropertyType::RemoteDeviceTimestamp => BluetoothProperty::RemoteDeviceTimestamp(),
531 _ => BluetoothProperty::Unknown(),
532 }
533 }
534 }
535
536 impl From<BluetoothProperty> for (Box<[u8]>, bindings::bt_property_t) {
from(prop: BluetoothProperty) -> Self537 fn from(prop: BluetoothProperty) -> Self {
538 let dvec: Vec<u8> = vec![0; prop.get_len()];
539 let mut data: Box<[u8]> = dvec.into_boxed_slice();
540 let prop = bindings::bt_property_t {
541 type_: prop.get_type().into(),
542 len: prop.get_len() as i32,
543 val: prop.get_data_ptr(&mut data) as *mut std::os::raw::c_void,
544 };
545
546 (data, prop)
547 }
548 }
549
550 pub enum SupportedProfiles {
551 HidHost,
552 Hfp,
553 A2dp,
554 Gatt,
555 Sdp,
556 }
557
558 impl From<SupportedProfiles> for Vec<u8> {
from(item: SupportedProfiles) -> Self559 fn from(item: SupportedProfiles) -> Self {
560 match item {
561 SupportedProfiles::HidHost => "hidhost",
562 SupportedProfiles::Hfp => "hfp",
563 SupportedProfiles::A2dp => "a2dp",
564 SupportedProfiles::Gatt => "gatt",
565 SupportedProfiles::Sdp => "sdp",
566 }
567 .bytes()
568 .chain("\0".bytes())
569 .collect::<Vec<u8>>()
570 }
571 }
572
573 #[cxx::bridge(namespace = bluetooth::topshim::rust)]
574 mod ffi {
575 #[derive(Debug, Copy, Clone)]
576 pub struct RustRawAddress {
577 address: [u8; 6],
578 }
579
580 unsafe extern "C++" {
581 include!("btif/btif_shim.h");
582
583 // For converting init flags from Vec<String> to const char **
584 type InitFlags;
585
586 // Convert flgas into an InitFlags object
ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>587 fn ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>;
GetFlagsPtr(self: &InitFlags) -> *mut *const c_char588 fn GetFlagsPtr(self: &InitFlags) -> *mut *const c_char;
589 }
590 }
591
592 // Export the raw address type directly from the bindings
593 pub type FfiAddress = bindings::RawAddress;
594
595 /// A shared address structure that has the same representation as
596 /// bindings::RawAddress. Macros `deref_ffi_address` and `cast_to_ffi_address`
597 /// are used for transforming between bindings::RawAddress at ffi boundaries.
598 #[derive(Copy, Clone, Hash, Eq, PartialEq)]
599 #[repr(C)]
600 pub struct RawAddress {
601 pub val: [u8; 6],
602 }
603
604 impl Debug for RawAddress {
fmt(&self, f: &mut Formatter<'_>) -> Result605 fn fmt(&self, f: &mut Formatter<'_>) -> Result {
606 f.write_fmt(format_args!(
607 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
608 self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
609 ))
610 }
611 }
612
613 impl Default for RawAddress {
default() -> Self614 fn default() -> Self {
615 Self { val: [0; 6] }
616 }
617 }
618
619 impl ToString for RawAddress {
to_string(&self) -> String620 fn to_string(&self) -> String {
621 String::from(format!(
622 "{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
623 self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
624 ))
625 }
626 }
627
628 impl RawAddress {
629 /// Constructs a RawAddress from a slice of 6 bytes.
from_bytes(raw_addr: &[u8]) -> Option<RawAddress>630 pub fn from_bytes(raw_addr: &[u8]) -> Option<RawAddress> {
631 if raw_addr.len() != 6 {
632 return None;
633 }
634 let mut raw: [u8; 6] = [0; 6];
635 raw.copy_from_slice(raw_addr);
636 return Some(RawAddress { val: raw });
637 }
638
from_string<S: Into<String>>(addr: S) -> Option<RawAddress>639 pub fn from_string<S: Into<String>>(addr: S) -> Option<RawAddress> {
640 let addr: String = addr.into();
641 let s = addr.split(':').collect::<Vec<&str>>();
642
643 if s.len() != 6 {
644 return None;
645 }
646
647 let mut raw: [u8; 6] = [0; 6];
648 for i in 0..s.len() {
649 raw[i] = match u8::from_str_radix(s[i], 16) {
650 Ok(res) => res,
651 Err(_) => {
652 return None;
653 }
654 };
655 }
656
657 Some(RawAddress { val: raw })
658 }
659
to_byte_arr(&self) -> [u8; 6]660 pub fn to_byte_arr(&self) -> [u8; 6] {
661 self.val.clone()
662 }
663 }
664
665 #[macro_export]
666 macro_rules! deref_ffi_address {
667 ($ffi_addr:ident) => {
668 *($ffi_addr as *mut RawAddress)
669 };
670 }
671
672 #[macro_export]
673 macro_rules! deref_const_ffi_address {
674 ($ffi_addr:ident) => {
675 *($ffi_addr as *const RawAddress)
676 };
677 }
678
679 #[macro_export]
680 macro_rules! cast_to_ffi_address {
681 ($raw_addr:expr) => {
682 $raw_addr as *mut FfiAddress
683 };
684 }
685
686 #[macro_export]
687 macro_rules! cast_to_const_ffi_address {
688 ($raw_addr:expr) => {
689 $raw_addr as *const FfiAddress
690 };
691 }
692
693 /// An enum representing `bt_callbacks_t` from btif.
694 #[derive(Clone, Debug)]
695 pub enum BaseCallbacks {
696 AdapterState(BtState),
697 AdapterProperties(BtStatus, i32, Vec<BluetoothProperty>),
698 RemoteDeviceProperties(BtStatus, RawAddress, i32, Vec<BluetoothProperty>),
699 DeviceFound(i32, Vec<BluetoothProperty>),
700 DiscoveryState(BtDiscoveryState),
701 PinRequest(RawAddress, String, u32, bool),
702 SspRequest(RawAddress, String, u32, BtSspVariant, u32),
703 BondState(BtStatus, RawAddress, BtBondState, i32),
704 AddressConsolidate(RawAddress, RawAddress),
705 LeAddressAssociate(RawAddress, RawAddress),
706 AclState(BtStatus, RawAddress, BtAclState, BtTransport, BtHciErrorCode),
707 // Unimplemented so far:
708 // thread_evt_cb
709 // dut_mode_recv_cb
710 // le_test_mode_cb
711 // energy_info_cb
712 // link_quality_report_cb
713 // generate_local_oob_data_cb
714 // switch_buffer_size_cb
715 // switch_codec_cb
716 }
717
718 pub struct BaseCallbacksDispatcher {
719 pub dispatch: Box<dyn Fn(BaseCallbacks) + Send>,
720 }
721
722 type BaseCb = Arc<Mutex<BaseCallbacksDispatcher>>;
723
724 cb_variant!(BaseCb, adapter_state_cb -> BaseCallbacks::AdapterState, u32 -> BtState);
725 cb_variant!(BaseCb, adapter_properties_cb -> BaseCallbacks::AdapterProperties,
726 u32 -> BtStatus, i32, *mut bindings::bt_property_t, {
727 let _2 = ptr_to_vec(_2, _1 as usize);
728 });
729 cb_variant!(BaseCb, remote_device_properties_cb -> BaseCallbacks::RemoteDeviceProperties,
730 u32 -> BtStatus, *mut FfiAddress -> RawAddress, i32, *mut bindings::bt_property_t, {
731 let _1 = unsafe { *(_1 as *const RawAddress) };
732 let _3 = ptr_to_vec(_3, _2 as usize);
733 });
734 cb_variant!(BaseCb, device_found_cb -> BaseCallbacks::DeviceFound,
735 i32, *mut bindings::bt_property_t, {
736 let _1 = ptr_to_vec(_1, _0 as usize);
737 });
738 cb_variant!(BaseCb, discovery_state_cb -> BaseCallbacks::DiscoveryState,
739 bindings::bt_discovery_state_t -> BtDiscoveryState);
740 cb_variant!(BaseCb, pin_request_cb -> BaseCallbacks::PinRequest,
741 *mut FfiAddress, *mut bindings::bt_bdname_t, u32, bool, {
742 let _0 = unsafe { *(_0 as *const RawAddress)};
743 let _1 = String::from(unsafe{*_1});
744 });
745 cb_variant!(BaseCb, ssp_request_cb -> BaseCallbacks::SspRequest,
746 *mut FfiAddress, *mut bindings::bt_bdname_t, u32, bindings::bt_ssp_variant_t -> BtSspVariant, u32, {
747 let _0 = unsafe { *(_0 as *const RawAddress) };
748 let _1 = String::from(unsafe{*_1});
749 });
750 cb_variant!(BaseCb, bond_state_cb -> BaseCallbacks::BondState,
751 u32 -> BtStatus, *mut FfiAddress, bindings::bt_bond_state_t -> BtBondState, i32, {
752 let _1 = unsafe { *(_1 as *const RawAddress) };
753 });
754
755 cb_variant!(BaseCb, address_consolidate_cb -> BaseCallbacks::AddressConsolidate,
756 *mut FfiAddress, *mut FfiAddress, {
757 let _0 = unsafe { *(_0 as *const RawAddress) };
758 let _1 = unsafe { *(_1 as *const RawAddress) };
759 });
760
761 cb_variant!(BaseCb, le_address_associate_cb -> BaseCallbacks::LeAddressAssociate,
762 *mut FfiAddress, *mut FfiAddress, {
763 let _0 = unsafe { *(_0 as *const RawAddress) };
764 let _1 = unsafe { *(_1 as *const RawAddress) };
765 });
766
767 cb_variant!(BaseCb, acl_state_cb -> BaseCallbacks::AclState,
768 u32 -> BtStatus, *mut FfiAddress, bindings::bt_acl_state_t -> BtAclState, i32 -> BtTransport, bindings::bt_hci_error_code_t -> BtHciErrorCode, {
769 let _1 = unsafe { *(_1 as *const RawAddress) };
770 });
771
772 struct RawInterfaceWrapper {
773 pub raw: *const bindings::bt_interface_t,
774 }
775
776 unsafe impl Send for RawInterfaceWrapper {}
777
778 /// Macro to call functions via function pointers. Expects the self object to
779 /// have a raw interface wrapper at `self.internal`. The actual function call is
780 /// marked unsafe since it will need to dereference a C object. This can cause
781 /// segfaults if not validated beforehand.
782 ///
783 /// Example:
784 /// ccall!(self, foobar, arg1, arg2)
785 /// Expands to: unsafe {((*self.internal.raw).foobar.unwrap())(arg1, arg2)}
786 #[macro_export]
787 macro_rules! ccall {
788 ($self:ident,$fn_name:ident) => {
789 unsafe {
790 ((*$self.internal.raw).$fn_name.unwrap())()
791 }
792 };
793 ($self:ident,$fn_name:ident, $($args:expr),*) => {
794 unsafe {
795 ((*$self.internal.raw).$fn_name.unwrap())($($args),*)
796 }
797 };
798 }
799
800 /// Macro to call const functions via cxx. Expects the self object to have the
801 /// cxx object to be called at `self.internal_cxx`.
802 ///
803 /// Example:
804 /// cxxcall!(self, foobar, arg1, arg2)
805 /// Expands to: self.internal_cxx.foobar(arg1, arg2)
806 #[macro_export]
807 macro_rules! cxxcall {
808 ($self:expr,$fn_name:ident) => {
809 $self.internal_cxx.$fn_name()
810 };
811 ($self:expr,$fn_name:ident, $($args:expr),*) => {
812 $self.internal_cxx.$fn_name($($args),*)
813 };
814 }
815
816 /// Macro to call mutable functions via cxx. Mutable functions are always
817 /// required to be defined with `self: Pin<&mut Self>`. The self object must
818 /// have the cxx object at `self.internal_cxx`.
819 ///
820 /// Example:
821 /// mutcxxcall!(self, foobar, arg1, arg2)
822 /// Expands to: self.internal_cxx.pin_mut().foobar(arg1, arg2)
823 #[macro_export]
824 macro_rules! mutcxxcall {
825 ($self:expr,$fn_name:ident) => {
826 $self.internal_cxx.pin_mut().$fn_name()
827 };
828 ($self:expr,$fn_name:ident, $($args:expr),*) => {
829 $self.internal_cxx.pin_mut().$fn_name($($args),*)
830 };
831 }
832
833 /// Rust wrapper around `bt_interface_t`.
834 pub struct BluetoothInterface {
835 internal: RawInterfaceWrapper,
836
837 /// Set to true after `initialize` is called.
838 pub is_init: bool,
839
840 // Need to take ownership of callbacks so it doesn't get freed after init
841 callbacks: Option<Box<bindings::bt_callbacks_t>>,
842 }
843
844 impl BluetoothInterface {
is_initialized(&self) -> bool845 pub fn is_initialized(&self) -> bool {
846 self.is_init
847 }
848
849 /// Initialize the Bluetooth interface by setting up the underlying interface.
850 ///
851 /// # Arguments
852 ///
853 /// * `callbacks` - Dispatcher struct that accepts [`BaseCallbacks`]
854 /// * `init_flags` - List of flags sent to libbluetooth for init.
initialize( &mut self, callbacks: BaseCallbacksDispatcher, init_flags: Vec<String>, ) -> bool855 pub fn initialize(
856 &mut self,
857 callbacks: BaseCallbacksDispatcher,
858 init_flags: Vec<String>,
859 ) -> bool {
860 // Init flags need to be converted from string to null terminated bytes
861 let converted: cxx::UniquePtr<ffi::InitFlags> = ffi::ConvertFlags(init_flags);
862 let flags = (*converted).GetFlagsPtr();
863
864 if get_dispatchers().lock().unwrap().set::<BaseCb>(Arc::new(Mutex::new(callbacks))) {
865 panic!("Tried to set dispatcher for BaseCallbacks but it already existed");
866 }
867
868 // Fill up callbacks struct to pass to init function (will be copied so
869 // no need to worry about ownership)
870 let mut callbacks = Box::new(bindings::bt_callbacks_t {
871 size: 16 * 8,
872 adapter_state_changed_cb: Some(adapter_state_cb),
873 adapter_properties_cb: Some(adapter_properties_cb),
874 remote_device_properties_cb: Some(remote_device_properties_cb),
875 device_found_cb: Some(device_found_cb),
876 discovery_state_changed_cb: Some(discovery_state_cb),
877 pin_request_cb: Some(pin_request_cb),
878 ssp_request_cb: Some(ssp_request_cb),
879 bond_state_changed_cb: Some(bond_state_cb),
880 address_consolidate_cb: Some(address_consolidate_cb),
881 le_address_associate_cb: Some(le_address_associate_cb),
882 acl_state_changed_cb: Some(acl_state_cb),
883 thread_evt_cb: None,
884 dut_mode_recv_cb: None,
885 le_test_mode_cb: None,
886 energy_info_cb: None,
887 link_quality_report_cb: None,
888 generate_local_oob_data_cb: None,
889 switch_buffer_size_cb: None,
890 switch_codec_cb: None,
891 });
892
893 let rawcb: *mut bindings::bt_callbacks_t = &mut *callbacks;
894
895 let (guest_mode, is_common_criteria_mode, config_compare_result, is_atv) =
896 (false, false, 0, false);
897
898 let init = ccall!(
899 self,
900 init,
901 rawcb,
902 guest_mode,
903 is_common_criteria_mode,
904 config_compare_result,
905 flags,
906 is_atv,
907 std::ptr::null()
908 );
909
910 self.is_init = init == 0;
911 self.callbacks = Some(callbacks);
912
913 return self.is_init;
914 }
915
cleanup(&self)916 pub fn cleanup(&self) {
917 ccall!(self, cleanup)
918 }
919
enable(&self) -> i32920 pub fn enable(&self) -> i32 {
921 ccall!(self, enable)
922 }
923
disable(&self) -> i32924 pub fn disable(&self) -> i32 {
925 ccall!(self, disable)
926 }
927
get_adapter_properties(&self) -> i32928 pub fn get_adapter_properties(&self) -> i32 {
929 ccall!(self, get_adapter_properties)
930 }
931
get_adapter_property(&self, prop: BtPropertyType) -> i32932 pub fn get_adapter_property(&self, prop: BtPropertyType) -> i32 {
933 let converted_type = bindings::bt_property_type_t::from(prop);
934 ccall!(self, get_adapter_property, converted_type)
935 }
936
set_adapter_property(&self, prop: BluetoothProperty) -> i32937 pub fn set_adapter_property(&self, prop: BluetoothProperty) -> i32 {
938 let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
939 ccall!(self, set_adapter_property, &prop_pair.1)
940 }
941
get_remote_device_properties(&self, addr: &mut RawAddress) -> i32942 pub fn get_remote_device_properties(&self, addr: &mut RawAddress) -> i32 {
943 let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
944 ccall!(self, get_remote_device_properties, ffi_addr)
945 }
946
get_remote_device_property( &self, addr: &mut RawAddress, prop_type: BtPropertyType, ) -> i32947 pub fn get_remote_device_property(
948 &self,
949 addr: &mut RawAddress,
950 prop_type: BtPropertyType,
951 ) -> i32 {
952 let converted_type = bindings::bt_property_type_t::from(prop_type);
953 let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
954 ccall!(self, get_remote_device_property, ffi_addr, converted_type)
955 }
956
set_remote_device_property( &self, addr: &mut RawAddress, prop: BluetoothProperty, ) -> i32957 pub fn set_remote_device_property(
958 &self,
959 addr: &mut RawAddress,
960 prop: BluetoothProperty,
961 ) -> i32 {
962 let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
963 let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
964 ccall!(self, set_remote_device_property, ffi_addr, &prop_pair.1)
965 }
966
get_remote_services(&self, addr: &mut RawAddress, transport: BtTransport) -> i32967 pub fn get_remote_services(&self, addr: &mut RawAddress, transport: BtTransport) -> i32 {
968 let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
969 ccall!(self, get_remote_services, ffi_addr, transport.to_i32().unwrap())
970 }
971
start_discovery(&self) -> i32972 pub fn start_discovery(&self) -> i32 {
973 ccall!(self, start_discovery)
974 }
975
cancel_discovery(&self) -> i32976 pub fn cancel_discovery(&self) -> i32 {
977 ccall!(self, cancel_discovery)
978 }
979
create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32980 pub fn create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32 {
981 let ctransport: i32 = transport.into();
982 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
983 ccall!(self, create_bond, ffi_addr, ctransport)
984 }
985
remove_bond(&self, addr: &RawAddress) -> i32986 pub fn remove_bond(&self, addr: &RawAddress) -> i32 {
987 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
988 ccall!(self, remove_bond, ffi_addr)
989 }
990
cancel_bond(&self, addr: &RawAddress) -> i32991 pub fn cancel_bond(&self, addr: &RawAddress) -> i32 {
992 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
993 ccall!(self, cancel_bond, ffi_addr)
994 }
995
get_connection_state(&self, addr: &RawAddress) -> u32996 pub fn get_connection_state(&self, addr: &RawAddress) -> u32 {
997 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
998 ccall!(self, get_connection_state, ffi_addr).to_u32().unwrap()
999 }
1000
pin_reply( &self, addr: &RawAddress, accept: u8, pin_len: u8, pin_code: &mut BtPinCode, ) -> i321001 pub fn pin_reply(
1002 &self,
1003 addr: &RawAddress,
1004 accept: u8,
1005 pin_len: u8,
1006 pin_code: &mut BtPinCode,
1007 ) -> i32 {
1008 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
1009 ccall!(self, pin_reply, ffi_addr, accept, pin_len, pin_code)
1010 }
1011
ssp_reply( &self, addr: &RawAddress, variant: BtSspVariant, accept: u8, passkey: u32, ) -> i321012 pub fn ssp_reply(
1013 &self,
1014 addr: &RawAddress,
1015 variant: BtSspVariant,
1016 accept: u8,
1017 passkey: u32,
1018 ) -> i32 {
1019 let cvariant = bindings::bt_ssp_variant_t::from(variant);
1020 let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
1021 ccall!(self, ssp_reply, ffi_addr, cvariant, accept, passkey)
1022 }
1023
clear_event_filter(&self) -> i321024 pub fn clear_event_filter(&self) -> i32 {
1025 ccall!(self, clear_event_filter)
1026 }
1027
get_profile_interface( &self, profile: SupportedProfiles, ) -> *const std::os::raw::c_void1028 pub(crate) fn get_profile_interface(
1029 &self,
1030 profile: SupportedProfiles,
1031 ) -> *const std::os::raw::c_void {
1032 let cprofile = Vec::<u8>::from(profile);
1033 ccall!(
1034 self,
1035 get_profile_interface,
1036 cprofile.as_slice().as_ptr() as *const std::os::raw::c_char
1037 )
1038 }
1039
as_raw_ptr(&self) -> *const u81040 pub(crate) fn as_raw_ptr(&self) -> *const u8 {
1041 self.internal.raw as *const u8
1042 }
1043 }
1044
get_btinterface() -> Option<BluetoothInterface>1045 pub fn get_btinterface() -> Option<BluetoothInterface> {
1046 let mut ret: Option<BluetoothInterface> = None;
1047 let mut ifptr: *const bindings::bt_interface_t = std::ptr::null();
1048
1049 unsafe {
1050 if bindings::hal_util_load_bt_library(&mut ifptr) == 0 {
1051 ret = Some(BluetoothInterface {
1052 internal: RawInterfaceWrapper { raw: ifptr },
1053 is_init: false,
1054 callbacks: None,
1055 });
1056 }
1057 }
1058
1059 ret
1060 }
1061
1062 // Turns C-array T[] to Vec<U>.
ptr_to_vec<T: Copy, U: From<T>>(start: *const T, length: usize) -> Vec<U>1063 pub(crate) fn ptr_to_vec<T: Copy, U: From<T>>(start: *const T, length: usize) -> Vec<U> {
1064 unsafe { (0..length).map(|i| U::from(*start.offset(i as isize))).collect::<Vec<U>>() }
1065 }
1066
1067 #[cfg(test)]
1068 mod tests {
1069 use super::*;
1070 use std::mem;
1071
1072 #[test]
test_addr_size()1073 fn test_addr_size() {
1074 assert_eq!(mem::size_of::<RawAddress>(), mem::size_of::<FfiAddress>());
1075 }
1076
1077 #[test]
test_offset()1078 fn test_offset() {
1079 let r = RawAddress { val: [1, 2, 3, 4, 5, 6] };
1080 let f = FfiAddress { address: [1, 2, 3, 4, 5, 6] };
1081 assert_eq!(
1082 &f as *const _ as usize - &f.address as *const _ as usize,
1083 &r as *const _ as usize - &r.val as *const _ as usize
1084 );
1085 }
1086
1087 #[test]
test_alignment()1088 fn test_alignment() {
1089 assert_eq!(std::mem::align_of::<RawAddress>(), std::mem::align_of::<FfiAddress>());
1090 }
1091
make_bdname_from_slice(slice: &[u8]) -> bindings::bt_bdname_t1092 fn make_bdname_from_slice(slice: &[u8]) -> bindings::bt_bdname_t {
1093 // Length of slice must be less than bd_name max
1094 assert!(slice.len() <= 249);
1095
1096 let mut bdname = bindings::bt_bdname_t { name: [128; 249] };
1097
1098 for (i, v) in slice.iter().enumerate() {
1099 bdname.name[i] = v.clone();
1100 }
1101
1102 bdname
1103 }
1104
1105 #[test]
test_bdname_conversions()1106 fn test_bdname_conversions() {
1107 let hello_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79, 0]);
1108 assert_eq!("HELLO".to_string(), String::from(hello_bdname));
1109
1110 let empty_bdname = make_bdname_from_slice(&[0]);
1111 assert_eq!("".to_string(), String::from(empty_bdname));
1112
1113 let no_nullterm_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79]);
1114 assert_eq!("".to_string(), String::from(no_nullterm_bdname));
1115
1116 let invalid_bdname = make_bdname_from_slice(&[128; 249]);
1117 assert_eq!("".to_string(), String::from(invalid_bdname));
1118 }
1119
1120 #[test]
test_ptr_to_vec()1121 fn test_ptr_to_vec() {
1122 let arr: [i32; 3] = [1, 2, 3];
1123 let vec: Vec<i32> = ptr_to_vec(arr.as_ptr(), arr.len());
1124 let expected: Vec<i32> = vec![1, 2, 3];
1125 assert_eq!(expected, vec);
1126 }
1127
1128 #[test]
test_property_with_string_conversions()1129 fn test_property_with_string_conversions() {
1130 {
1131 let bdname = BluetoothProperty::BdName("FooBar".into());
1132 let prop_pair: (Box<[u8]>, bindings::bt_property_t) = bdname.into();
1133 let converted: BluetoothProperty = prop_pair.1.into();
1134 assert!(match converted {
1135 BluetoothProperty::BdName(name) => "FooBar".to_string() == name,
1136 _ => false,
1137 });
1138 }
1139
1140 {
1141 let orig_record = BtServiceRecord {
1142 uuid: Uuid { uu: [0; 16] },
1143 channel: 3,
1144 name: "FooBar".to_string(),
1145 };
1146 let service_record = BluetoothProperty::ServiceRecord(orig_record.clone());
1147 let prop_pair: (Box<[u8]>, bindings::bt_property_t) = service_record.into();
1148 let converted: BluetoothProperty = prop_pair.1.into();
1149 assert!(match converted {
1150 BluetoothProperty::ServiceRecord(sr) => {
1151 sr.uuid == orig_record.uuid
1152 && sr.channel == orig_record.channel
1153 && sr.name == orig_record.name
1154 }
1155 _ => false,
1156 });
1157 }
1158
1159 {
1160 let rfname = BluetoothProperty::RemoteFriendlyName("FooBizz".into());
1161 let prop_pair: (Box<[u8]>, bindings::bt_property_t) = rfname.into();
1162 let converted: BluetoothProperty = prop_pair.1.into();
1163 assert!(match converted {
1164 BluetoothProperty::RemoteFriendlyName(name) => "FooBizz".to_string() == name,
1165 _ => false,
1166 });
1167 }
1168 }
1169 }
1170