blob: 91cf7d7215defbd16645a8f497d4f8b1c6c0935d [file] [log] [blame]
//! Bluetooth interface shim
//!
//! This is a shim interface for calling the C++ bluetooth interface via Rust.
//!
use crate::bindings::root as bindings;
use crate::topstack::get_dispatchers;
use num_traits::cast::{FromPrimitive, ToPrimitive};
use std::cmp;
use std::fmt::{Debug, Formatter, Result};
use std::mem;
use std::os::raw::c_char;
use std::sync::{Arc, Mutex};
use std::vec::Vec;
use topshim_macros::cb_variant;
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtState {
Off = 0,
On,
}
impl From<bindings::bt_state_t> for BtState {
fn from(item: bindings::bt_state_t) -> Self {
BtState::from_u32(item).unwrap_or_else(|| BtState::Off)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtTransport {
Auto = 0,
Bredr,
Le,
}
impl From<i32> for BtTransport {
fn from(item: i32) -> Self {
BtTransport::from_i32(item).unwrap_or_else(|| BtTransport::Auto)
}
}
impl From<BtTransport> for i32 {
fn from(item: BtTransport) -> Self {
item.to_i32().unwrap_or_else(|| 0)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtSspVariant {
PasskeyConfirmation = 0,
PasskeyEntry,
Consent,
PasskeyNotification,
}
impl From<bindings::bt_ssp_variant_t> for BtSspVariant {
fn from(item: bindings::bt_ssp_variant_t) -> Self {
BtSspVariant::from_u32(item).unwrap_or_else(|| BtSspVariant::PasskeyConfirmation)
}
}
impl From<BtSspVariant> for bindings::bt_ssp_variant_t {
fn from(item: BtSspVariant) -> Self {
item.to_u32().unwrap_or_else(|| 0)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtBondState {
NotBonded = 0,
Bonding,
Bonded,
}
impl From<bindings::bt_bond_state_t> for BtBondState {
fn from(item: bindings::bt_bond_state_t) -> Self {
BtBondState::from_u32(item).unwrap_or_else(|| BtBondState::NotBonded)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtConnectionState {
NotConnected = 0,
ConnectedOnly = 1,
EncryptedBredr = 3,
EncryptedLe = 5,
}
impl From<i32> for BtConnectionState {
fn from(item: i32) -> Self {
let fallback = if item > 0 {
BtConnectionState::ConnectedOnly
} else {
BtConnectionState::NotConnected
};
BtConnectionState::from_i32(item).unwrap_or(fallback)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtAclState {
Connected = 0,
Disconnected,
}
impl From<bindings::bt_acl_state_t> for BtAclState {
fn from(item: bindings::bt_acl_state_t) -> Self {
BtAclState::from_u32(item).unwrap_or_else(|| BtAclState::Disconnected)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtDeviceType {
Bredr,
Ble,
Dual,
}
#[derive(Clone, Debug, Eq, Hash, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtPropertyType {
BdName = 0x1,
BdAddr,
Uuids,
ClassOfDevice,
TypeOfDevice,
ServiceRecord,
AdapterScanMode,
AdapterBondedDevices,
AdapterDiscoveryTimeout,
RemoteFriendlyName,
RemoteRssi,
RemoteVersionInfo,
LocalLeFeatures,
LocalIoCaps,
LocalIoCapsBle,
DynamicAudioBuffer,
Unknown = 0xFE,
RemoteDeviceTimestamp = 0xFF,
}
impl From<u32> for BtPropertyType {
fn from(item: u32) -> Self {
BtPropertyType::from_u32(item).unwrap_or_else(|| BtPropertyType::Unknown)
}
}
impl From<BtPropertyType> for u32 {
fn from(item: BtPropertyType) -> Self {
item.to_u32().unwrap_or_else(|| 0)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtDiscoveryState {
Stopped = 0x0,
Started,
}
impl From<u32> for BtDiscoveryState {
fn from(item: u32) -> Self {
BtDiscoveryState::from_u32(item).unwrap_or_else(|| BtDiscoveryState::Stopped)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtStatus {
Success = 0,
Fail,
NotReady,
NoMemory,
Busy,
Done,
Unsupported,
InvalidParam,
Unhandled,
AuthFailure,
RemoteDeviceDown,
AuthRejected,
JniEnvironmentError,
JniThreadAttachError,
WakeLockError,
// Any statuses that couldn't be cleanly converted
Unknown = 0xff,
}
pub fn ascii_to_string(data: &[u8], length: usize) -> String {
// We need to reslice data because from_utf8 tries to interpret the
// whole slice and not just what is before the null terminated portion
let ascii = data
.iter()
.enumerate()
.take_while(|&(pos, &c)| c != 0 && pos < length)
.map(|(_pos, &x)| x.clone())
.collect::<Vec<u8>>();
return String::from_utf8(ascii).unwrap_or_default();
}
fn u32_from_bytes(item: &[u8]) -> u32 {
let mut u: [u8; 4] = [0; 4];
u.copy_from_slice(&item[0..4]);
u32::from_ne_bytes(u)
}
impl From<bindings::bt_status_t> for BtStatus {
fn from(item: bindings::bt_status_t) -> Self {
match BtStatus::from_u32(item) {
Some(x) => x,
_ => BtStatus::Unknown,
}
}
}
impl From<bindings::bt_bdname_t> for String {
fn from(item: bindings::bt_bdname_t) -> Self {
ascii_to_string(&item.name, item.name.len())
}
}
#[derive(Debug, Clone)]
pub struct BtServiceRecord {
pub uuid: bindings::bluetooth::Uuid,
pub channel: u16,
pub name: String,
}
impl From<bindings::bt_service_record_t> for BtServiceRecord {
fn from(item: bindings::bt_service_record_t) -> Self {
let name = item.name.iter().map(|&x| x.clone() as u8).collect::<Vec<u8>>();
BtServiceRecord {
uuid: item.uuid,
channel: item.channel,
name: ascii_to_string(name.as_slice(), name.len()),
}
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtScanMode {
None_,
Connectable,
ConnectableDiscoverable,
}
impl From<bindings::bt_scan_mode_t> for BtScanMode {
fn from(item: bindings::bt_scan_mode_t) -> Self {
BtScanMode::from_u32(item).unwrap_or(BtScanMode::None_)
}
}
#[derive(Clone, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum BtIoCap {
Out,
InOut,
In,
None_,
KbDisp,
Max,
Unknown = 0xff,
}
impl From<bindings::bt_io_cap_t> for BtIoCap {
fn from(item: bindings::bt_io_cap_t) -> Self {
BtIoCap::from_u32(item).unwrap_or(BtIoCap::Unknown)
}
}
pub type BtHciErrorCode = u8;
pub type BtLocalLeFeatures = bindings::bt_local_le_features_t;
pub type BtPinCode = bindings::bt_pin_code_t;
pub type BtRemoteVersion = bindings::bt_remote_version_t;
pub type Uuid = bindings::bluetooth::Uuid;
pub type Uuid128Bit = bindings::bluetooth::Uuid_UUID128Bit;
/// All supported Bluetooth properties after conversion.
#[derive(Debug, Clone)]
pub enum BluetoothProperty {
BdName(String),
BdAddr(RawAddress),
Uuids(Vec<Uuid>),
ClassOfDevice(u32),
TypeOfDevice(BtDeviceType),
ServiceRecord(BtServiceRecord),
AdapterScanMode(BtScanMode),
AdapterBondedDevices(Vec<RawAddress>),
AdapterDiscoveryTimeout(u32),
RemoteFriendlyName(String),
RemoteRssi(i8),
RemoteVersionInfo(BtRemoteVersion),
LocalLeFeatures(BtLocalLeFeatures),
LocalIoCaps(BtIoCap),
LocalIoCapsBle(BtIoCap),
DynamicAudioBuffer(),
RemoteDeviceTimestamp(),
Unknown(),
}
/// Wherever names are sent in bindings::bt_property_t, the size of the character
/// arrays are 256. Keep one extra byte for null termination.
const PROPERTY_NAME_MAX: usize = 255;
impl BluetoothProperty {
pub fn get_type(&self) -> BtPropertyType {
match &*self {
BluetoothProperty::BdName(_) => BtPropertyType::BdName,
BluetoothProperty::BdAddr(_) => BtPropertyType::BdAddr,
BluetoothProperty::Uuids(_) => BtPropertyType::Uuids,
BluetoothProperty::ClassOfDevice(_) => BtPropertyType::ClassOfDevice,
BluetoothProperty::TypeOfDevice(_) => BtPropertyType::TypeOfDevice,
BluetoothProperty::ServiceRecord(_) => BtPropertyType::ServiceRecord,
BluetoothProperty::AdapterScanMode(_) => BtPropertyType::AdapterScanMode,
BluetoothProperty::AdapterBondedDevices(_) => BtPropertyType::AdapterBondedDevices,
BluetoothProperty::AdapterDiscoveryTimeout(_) => {
BtPropertyType::AdapterDiscoveryTimeout
}
BluetoothProperty::RemoteFriendlyName(_) => BtPropertyType::RemoteFriendlyName,
BluetoothProperty::RemoteRssi(_) => BtPropertyType::RemoteRssi,
BluetoothProperty::RemoteVersionInfo(_) => BtPropertyType::RemoteVersionInfo,
BluetoothProperty::LocalLeFeatures(_) => BtPropertyType::LocalLeFeatures,
BluetoothProperty::LocalIoCaps(_) => BtPropertyType::LocalIoCaps,
BluetoothProperty::LocalIoCapsBle(_) => BtPropertyType::LocalIoCapsBle,
BluetoothProperty::DynamicAudioBuffer() => BtPropertyType::DynamicAudioBuffer,
BluetoothProperty::RemoteDeviceTimestamp() => BtPropertyType::RemoteDeviceTimestamp,
BluetoothProperty::Unknown() => BtPropertyType::Unknown,
}
}
fn get_len(&self) -> usize {
match &*self {
BluetoothProperty::BdName(name) => cmp::min(PROPERTY_NAME_MAX, name.len() + 1),
BluetoothProperty::BdAddr(addr) => addr.val.len(),
BluetoothProperty::Uuids(uulist) => uulist.len() * mem::size_of::<Uuid>(),
BluetoothProperty::ClassOfDevice(_) => mem::size_of::<u32>(),
BluetoothProperty::TypeOfDevice(_) => mem::size_of::<BtDeviceType>(),
BluetoothProperty::ServiceRecord(rec) => {
mem::size_of::<BtServiceRecord>() + cmp::min(PROPERTY_NAME_MAX, rec.name.len() + 1)
}
BluetoothProperty::AdapterScanMode(_) => mem::size_of::<BtScanMode>(),
BluetoothProperty::AdapterBondedDevices(devlist) => {
devlist.len() * mem::size_of::<RawAddress>()
}
BluetoothProperty::AdapterDiscoveryTimeout(_) => mem::size_of::<u32>(),
BluetoothProperty::RemoteFriendlyName(name) => {
cmp::min(PROPERTY_NAME_MAX, name.len() + 1)
}
BluetoothProperty::RemoteRssi(_) => mem::size_of::<i8>(),
BluetoothProperty::RemoteVersionInfo(_) => mem::size_of::<BtRemoteVersion>(),
BluetoothProperty::LocalLeFeatures(_) => mem::size_of::<BtLocalLeFeatures>(),
BluetoothProperty::LocalIoCaps(_) => mem::size_of::<BtIoCap>(),
BluetoothProperty::LocalIoCapsBle(_) => mem::size_of::<BtIoCap>(),
// TODO(abps) - Figure out sizes for these
BluetoothProperty::DynamicAudioBuffer() => 0,
BluetoothProperty::RemoteDeviceTimestamp() => 0,
BluetoothProperty::Unknown() => 0,
}
}
// Given a mutable array, this will copy the data to that array and return a
// pointer to it.
//
// The lifetime of the returned pointer is tied to that of the slice given.
fn get_data_ptr<'a>(&'a self, data: &'a mut [u8]) -> *mut u8 {
let len = self.get_len();
match &*self {
BluetoothProperty::BdName(name) => {
data.copy_from_slice(&name.as_bytes()[0..len]);
}
BluetoothProperty::BdAddr(addr) => {
data.copy_from_slice(&addr.val);
}
BluetoothProperty::Uuids(uulist) => {
for (idx, &uuid) in uulist.iter().enumerate() {
let start = idx * mem::size_of::<Uuid>();
let end = start + mem::size_of::<Uuid>();
data[start..end].copy_from_slice(&uuid.uu);
}
}
BluetoothProperty::ClassOfDevice(cod) => {
data.copy_from_slice(&cod.to_ne_bytes());
}
BluetoothProperty::TypeOfDevice(tod) => {
data.copy_from_slice(&BtDeviceType::to_u32(tod).unwrap_or_default().to_ne_bytes());
}
BluetoothProperty::ServiceRecord(sr) => {
// Do an unsafe cast to binding:: type and assign the values
// The underlying memory location is provided by |data| which will
// have enough space because it uses get_len()
let mut record =
unsafe { &mut *(data.as_mut_ptr() as *mut bindings::bt_service_record_t) };
record.uuid = sr.uuid;
record.channel = sr.channel;
let name_len = len - mem::size_of::<BtServiceRecord>();
record.name.copy_from_slice(
&(sr.name.as_bytes().iter().map(|x| *x as c_char).collect::<Vec<c_char>>())
[0..name_len],
);
}
BluetoothProperty::AdapterScanMode(sm) => {
data.copy_from_slice(&BtScanMode::to_u32(sm).unwrap_or_default().to_ne_bytes());
}
BluetoothProperty::AdapterBondedDevices(devlist) => {
for (idx, &dev) in devlist.iter().enumerate() {
let start = idx * mem::size_of::<RawAddress>();
let end = idx + mem::size_of::<RawAddress>();
data[start..end].copy_from_slice(&dev.val);
}
}
BluetoothProperty::AdapterDiscoveryTimeout(timeout) => {
data.copy_from_slice(&timeout.to_ne_bytes());
}
BluetoothProperty::RemoteFriendlyName(name) => {
data.copy_from_slice(&name.as_bytes()[0..len]);
}
BluetoothProperty::RemoteRssi(rssi) => {
data[0] = *rssi as u8;
}
BluetoothProperty::RemoteVersionInfo(rvi) => {
let ptr: *const BtRemoteVersion = rvi;
let slice = unsafe {
std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtRemoteVersion>())
};
data.copy_from_slice(&slice);
}
BluetoothProperty::LocalLeFeatures(llf) => {
let ptr: *const BtLocalLeFeatures = llf;
let slice = unsafe {
std::slice::from_raw_parts(ptr as *mut u8, mem::size_of::<BtLocalLeFeatures>())
};
data.copy_from_slice(&slice);
}
BluetoothProperty::LocalIoCaps(iocap) => {
data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
}
BluetoothProperty::LocalIoCapsBle(iocap) => {
data.copy_from_slice(&BtIoCap::to_u32(iocap).unwrap_or_default().to_ne_bytes());
}
BluetoothProperty::DynamicAudioBuffer() => (),
BluetoothProperty::RemoteDeviceTimestamp() => (),
BluetoothProperty::Unknown() => (),
};
data.as_mut_ptr()
}
}
// TODO(abps) - Check that sizes are correct when given a BtProperty
impl From<bindings::bt_property_t> for BluetoothProperty {
fn from(prop: bindings::bt_property_t) -> Self {
let slice: &[u8] =
unsafe { std::slice::from_raw_parts(prop.val as *mut u8, prop.len as usize) };
let len = prop.len as usize;
match BtPropertyType::from(prop.type_) {
BtPropertyType::BdName => BluetoothProperty::BdName(ascii_to_string(slice, len)),
BtPropertyType::BdAddr => {
BluetoothProperty::BdAddr(RawAddress::from_bytes(slice).unwrap_or_default())
}
BtPropertyType::Uuids => {
let count = len / mem::size_of::<Uuid>();
BluetoothProperty::Uuids(ptr_to_vec(prop.val as *mut Uuid, count))
}
BtPropertyType::ClassOfDevice => {
BluetoothProperty::ClassOfDevice(u32_from_bytes(slice))
}
BtPropertyType::TypeOfDevice => BluetoothProperty::TypeOfDevice(
BtDeviceType::from_u32(u32_from_bytes(slice)).unwrap_or(BtDeviceType::Bredr),
),
BtPropertyType::ServiceRecord => {
let v = unsafe { *(prop.val as *const bindings::bt_service_record_t) };
BluetoothProperty::ServiceRecord(BtServiceRecord::from(v))
}
BtPropertyType::AdapterScanMode => BluetoothProperty::AdapterScanMode(
BtScanMode::from_u32(u32_from_bytes(slice)).unwrap_or(BtScanMode::None_),
),
BtPropertyType::AdapterBondedDevices => {
let count = len / mem::size_of::<RawAddress>();
BluetoothProperty::AdapterBondedDevices(ptr_to_vec(
prop.val as *mut RawAddress,
count,
))
}
BtPropertyType::AdapterDiscoveryTimeout => {
BluetoothProperty::AdapterDiscoveryTimeout(u32_from_bytes(slice))
}
BtPropertyType::RemoteFriendlyName => {
BluetoothProperty::RemoteFriendlyName(ascii_to_string(slice, len))
}
BtPropertyType::RemoteRssi => BluetoothProperty::RemoteRssi(slice[0] as i8),
BtPropertyType::RemoteVersionInfo => {
let v = unsafe { *(prop.val as *const BtRemoteVersion) };
BluetoothProperty::RemoteVersionInfo(v.clone())
}
BtPropertyType::LocalLeFeatures => {
let v = unsafe { *(prop.val as *const BtLocalLeFeatures) };
BluetoothProperty::LocalLeFeatures(v.clone())
}
BtPropertyType::LocalIoCaps => BluetoothProperty::LocalIoCaps(
BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
),
BtPropertyType::LocalIoCapsBle => BluetoothProperty::LocalIoCapsBle(
BtIoCap::from_u32(u32_from_bytes(slice)).unwrap_or(BtIoCap::Unknown),
),
// TODO(abps) - Figure out if these values should actually have contents
BtPropertyType::DynamicAudioBuffer => BluetoothProperty::DynamicAudioBuffer(),
BtPropertyType::RemoteDeviceTimestamp => BluetoothProperty::RemoteDeviceTimestamp(),
_ => BluetoothProperty::Unknown(),
}
}
}
impl From<BluetoothProperty> for (Box<[u8]>, bindings::bt_property_t) {
fn from(prop: BluetoothProperty) -> Self {
let dvec: Vec<u8> = vec![0; prop.get_len()];
let mut data: Box<[u8]> = dvec.into_boxed_slice();
let prop = bindings::bt_property_t {
type_: prop.get_type().into(),
len: prop.get_len() as i32,
val: prop.get_data_ptr(&mut data) as *mut std::os::raw::c_void,
};
(data, prop)
}
}
pub enum SupportedProfiles {
HidHost,
Hfp,
A2dp,
Gatt,
Sdp,
}
impl From<SupportedProfiles> for Vec<u8> {
fn from(item: SupportedProfiles) -> Self {
match item {
SupportedProfiles::HidHost => "hidhost",
SupportedProfiles::Hfp => "hfp",
SupportedProfiles::A2dp => "a2dp",
SupportedProfiles::Gatt => "gatt",
SupportedProfiles::Sdp => "sdp",
}
.bytes()
.chain("\0".bytes())
.collect::<Vec<u8>>()
}
}
#[cxx::bridge(namespace = bluetooth::topshim::rust)]
mod ffi {
unsafe extern "C++" {
include!("btif/btif_shim.h");
// For converting init flags from Vec<String> to const char **
type InitFlags;
// Convert flgas into an InitFlags object
fn ConvertFlags(flags: Vec<String>) -> UniquePtr<InitFlags>;
fn GetFlagsPtr(self: &InitFlags) -> *mut *const c_char;
}
}
// Export the raw address type directly from the bindings
pub type FfiAddress = bindings::RawAddress;
/// A shared address structure that has the same representation as
/// bindings::RawAddress. Macros `deref_ffi_address` and `cast_to_ffi_address`
/// are used for transforming between bindings::RawAddress at ffi boundaries.
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
#[repr(C)]
pub struct RawAddress {
pub val: [u8; 6],
}
impl Debug for RawAddress {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
f.write_fmt(format_args!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
))
}
}
impl Default for RawAddress {
fn default() -> Self {
Self { val: [0; 6] }
}
}
impl ToString for RawAddress {
fn to_string(&self) -> String {
String::from(format!(
"{:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}",
self.val[0], self.val[1], self.val[2], self.val[3], self.val[4], self.val[5]
))
}
}
impl RawAddress {
/// Constructs a RawAddress from a slice of 6 bytes.
pub fn from_bytes(raw_addr: &[u8]) -> Option<RawAddress> {
if raw_addr.len() != 6 {
return None;
}
let mut raw: [u8; 6] = [0; 6];
raw.copy_from_slice(raw_addr);
return Some(RawAddress { val: raw });
}
pub fn from_string<S: Into<String>>(addr: S) -> Option<RawAddress> {
let addr: String = addr.into();
let s = addr.split(':').collect::<Vec<&str>>();
if s.len() != 6 {
return None;
}
let mut raw: [u8; 6] = [0; 6];
for i in 0..s.len() {
raw[i] = match u8::from_str_radix(s[i], 16) {
Ok(res) => res,
Err(_) => {
return None;
}
};
}
Some(RawAddress { val: raw })
}
pub fn to_byte_arr(&self) -> [u8; 6] {
self.val.clone()
}
}
#[macro_export]
macro_rules! deref_ffi_address {
($ffi_addr:ident) => {
*($ffi_addr as *mut RawAddress)
};
}
#[macro_export]
macro_rules! deref_const_ffi_address {
($ffi_addr:ident) => {
*($ffi_addr as *const RawAddress)
};
}
#[macro_export]
macro_rules! cast_to_ffi_address {
($raw_addr:expr) => {
$raw_addr as *mut FfiAddress
};
}
#[macro_export]
macro_rules! cast_to_const_ffi_address {
($raw_addr:expr) => {
$raw_addr as *const FfiAddress
};
}
#[derive(Clone, Debug)]
pub enum BaseCallbacks {
AdapterState(BtState),
AdapterProperties(BtStatus, i32, Vec<BluetoothProperty>),
RemoteDeviceProperties(BtStatus, RawAddress, i32, Vec<BluetoothProperty>),
DeviceFound(i32, Vec<BluetoothProperty>),
DiscoveryState(BtDiscoveryState),
PinRequest(RawAddress, String, u32, bool),
SspRequest(RawAddress, String, u32, BtSspVariant, u32),
BondState(BtStatus, RawAddress, BtBondState, i32),
AclState(BtStatus, RawAddress, BtAclState, BtTransport, BtHciErrorCode),
// Unimplemented so far:
// thread_evt_cb
// dut_mode_recv_cb
// le_test_mode_cb
// energy_info_cb
// link_quality_report_cb
// generate_local_oob_data_cb
}
pub struct BaseCallbacksDispatcher {
pub dispatch: Box<dyn Fn(BaseCallbacks) + Send>,
}
type BaseCb = Arc<Mutex<BaseCallbacksDispatcher>>;
cb_variant!(BaseCb, adapter_state_cb -> BaseCallbacks::AdapterState, u32 -> BtState);
cb_variant!(BaseCb, adapter_properties_cb -> BaseCallbacks::AdapterProperties,
u32 -> BtStatus, i32, *mut bindings::bt_property_t, {
let _2 = ptr_to_vec(_2, _1 as usize);
});
cb_variant!(BaseCb, remote_device_properties_cb -> BaseCallbacks::RemoteDeviceProperties,
u32 -> BtStatus, *mut FfiAddress -> RawAddress, i32, *mut bindings::bt_property_t, {
let _1 = unsafe { *(_1 as *const RawAddress) };
let _3 = ptr_to_vec(_3, _2 as usize);
});
cb_variant!(BaseCb, device_found_cb -> BaseCallbacks::DeviceFound,
i32, *mut bindings::bt_property_t, {
let _1 = ptr_to_vec(_1, _0 as usize);
});
cb_variant!(BaseCb, discovery_state_cb -> BaseCallbacks::DiscoveryState,
bindings::bt_discovery_state_t -> BtDiscoveryState);
cb_variant!(BaseCb, pin_request_cb -> BaseCallbacks::PinRequest,
*mut FfiAddress, *mut bindings::bt_bdname_t, u32, bool, {
let _0 = unsafe { *(_0 as *const RawAddress)};
let _1 = String::from(unsafe{*_1});
});
cb_variant!(BaseCb, ssp_request_cb -> BaseCallbacks::SspRequest,
*mut FfiAddress, *mut bindings::bt_bdname_t, u32, bindings::bt_ssp_variant_t -> BtSspVariant, u32, {
let _0 = unsafe { *(_0 as *const RawAddress) };
let _1 = String::from(unsafe{*_1});
});
cb_variant!(BaseCb, bond_state_cb -> BaseCallbacks::BondState,
u32 -> BtStatus, *mut FfiAddress, bindings::bt_bond_state_t -> BtBondState, i32, {
let _1 = unsafe { *(_1 as *const RawAddress) };
});
cb_variant!(BaseCb, acl_state_cb -> BaseCallbacks::AclState,
u32 -> BtStatus, *mut FfiAddress, bindings::bt_acl_state_t -> BtAclState, i32 -> BtTransport, bindings::bt_hci_error_code_t -> BtHciErrorCode, {
let _1 = unsafe { *(_1 as *const RawAddress) };
});
struct RawInterfaceWrapper {
pub raw: *const bindings::bt_interface_t,
}
unsafe impl Send for RawInterfaceWrapper {}
pub struct BluetoothInterface {
internal: RawInterfaceWrapper,
pub is_init: bool,
// Need to take ownership of callbacks so it doesn't get freed after init
callbacks: Option<Box<bindings::bt_callbacks_t>>,
}
#[macro_export]
macro_rules! ccall {
($self:ident,$fn_name:ident) => {
unsafe {
((*$self.internal.raw).$fn_name.unwrap())()
}
};
($self:ident,$fn_name:ident, $($args:expr),*) => {
unsafe {
((*$self.internal.raw).$fn_name.unwrap())($($args),*)
}
}
}
impl BluetoothInterface {
pub fn is_initialized(&self) -> bool {
self.is_init
}
pub fn initialize(
&mut self,
callbacks: BaseCallbacksDispatcher,
init_flags: Vec<String>,
) -> bool {
// Init flags need to be converted from string to null terminated bytes
let converted: cxx::UniquePtr<ffi::InitFlags> = ffi::ConvertFlags(init_flags);
let flags = (*converted).GetFlagsPtr();
if get_dispatchers().lock().unwrap().set::<BaseCb>(Arc::new(Mutex::new(callbacks))) {
panic!("Tried to set dispatcher for BaseCallbacks but it already existed");
}
// Fill up callbacks struct to pass to init function (will be copied so
// no need to worry about ownership)
let mut callbacks = Box::new(bindings::bt_callbacks_t {
size: 16 * 8,
adapter_state_changed_cb: Some(adapter_state_cb),
adapter_properties_cb: Some(adapter_properties_cb),
remote_device_properties_cb: Some(remote_device_properties_cb),
device_found_cb: Some(device_found_cb),
discovery_state_changed_cb: Some(discovery_state_cb),
pin_request_cb: Some(pin_request_cb),
ssp_request_cb: Some(ssp_request_cb),
bond_state_changed_cb: Some(bond_state_cb),
acl_state_changed_cb: Some(acl_state_cb),
thread_evt_cb: None,
dut_mode_recv_cb: None,
le_test_mode_cb: None,
energy_info_cb: None,
link_quality_report_cb: None,
generate_local_oob_data_cb: None,
});
let rawcb: *mut bindings::bt_callbacks_t = &mut *callbacks;
let (guest_mode, is_common_criteria_mode, config_compare_result, is_atv) =
(false, false, 0, false);
let init = ccall!(
self,
init,
rawcb,
guest_mode,
is_common_criteria_mode,
config_compare_result,
flags,
is_atv
);
self.is_init = init == 0;
self.callbacks = Some(callbacks);
return self.is_init;
}
pub fn cleanup(&self) {
ccall!(self, cleanup)
}
pub fn enable(&self) -> i32 {
ccall!(self, enable)
}
pub fn disable(&self) -> i32 {
ccall!(self, disable)
}
pub fn get_adapter_properties(&self) -> i32 {
ccall!(self, get_adapter_properties)
}
pub fn get_adapter_property(&self, prop: BtPropertyType) -> i32 {
let converted_type = bindings::bt_property_type_t::from(prop);
ccall!(self, get_adapter_property, converted_type)
}
pub fn set_adapter_property(&self, prop: BluetoothProperty) -> i32 {
let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
ccall!(self, set_adapter_property, &prop_pair.1)
}
pub fn get_remote_device_properties(&self, addr: &mut RawAddress) -> i32 {
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
ccall!(self, get_remote_device_properties, ffi_addr)
}
pub fn get_remote_device_property(
&self,
addr: &mut RawAddress,
prop_type: BtPropertyType,
) -> i32 {
let converted_type = bindings::bt_property_type_t::from(prop_type);
let ffi_addr = cast_to_ffi_address!(addr as *mut RawAddress);
ccall!(self, get_remote_device_property, ffi_addr, converted_type)
}
pub fn set_remote_device_property(
&self,
addr: &mut RawAddress,
prop: BluetoothProperty,
) -> i32 {
let prop_pair: (Box<[u8]>, bindings::bt_property_t) = prop.into();
let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
ccall!(self, set_remote_device_property, ffi_addr, &prop_pair.1)
}
pub fn get_remote_services(&self, addr: &mut RawAddress, transport: BtTransport) -> i32 {
let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress);
ccall!(self, get_remote_services, ffi_addr, transport.to_i32().unwrap())
}
pub fn start_discovery(&self) -> i32 {
ccall!(self, start_discovery)
}
pub fn cancel_discovery(&self) -> i32 {
ccall!(self, cancel_discovery)
}
pub fn create_bond(&self, addr: &RawAddress, transport: BtTransport) -> i32 {
let ctransport: i32 = transport.into();
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, create_bond, ffi_addr, ctransport)
}
pub fn remove_bond(&self, addr: &RawAddress) -> i32 {
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, remove_bond, ffi_addr)
}
pub fn cancel_bond(&self, addr: &RawAddress) -> i32 {
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, cancel_bond, ffi_addr)
}
pub fn get_connection_state(&self, addr: &RawAddress) -> u32 {
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, get_connection_state, ffi_addr).to_u32().unwrap()
}
pub fn pin_reply(
&self,
addr: &RawAddress,
accept: u8,
pin_len: u8,
pin_code: &mut BtPinCode,
) -> i32 {
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, pin_reply, ffi_addr, accept, pin_len, pin_code)
}
pub fn ssp_reply(
&self,
addr: &RawAddress,
variant: BtSspVariant,
accept: u8,
passkey: u32,
) -> i32 {
let cvariant = bindings::bt_ssp_variant_t::from(variant);
let ffi_addr = cast_to_const_ffi_address!(addr as *const RawAddress);
ccall!(self, ssp_reply, ffi_addr, cvariant, accept, passkey)
}
pub(crate) fn get_profile_interface(
&self,
profile: SupportedProfiles,
) -> *const std::os::raw::c_void {
let cprofile = Vec::<u8>::from(profile);
ccall!(
self,
get_profile_interface,
cprofile.as_slice().as_ptr() as *const std::os::raw::c_char
)
}
pub(crate) fn as_raw_ptr(&self) -> *const u8 {
self.internal.raw as *const u8
}
}
pub fn get_btinterface() -> Option<BluetoothInterface> {
let mut ret: Option<BluetoothInterface> = None;
let mut ifptr: *const bindings::bt_interface_t = std::ptr::null();
unsafe {
if bindings::hal_util_load_bt_library(&mut ifptr) == 0 {
ret = Some(BluetoothInterface {
internal: RawInterfaceWrapper { raw: ifptr },
is_init: false,
callbacks: None,
});
}
}
ret
}
// Turns C-array T[] to Vec<U>.
pub(crate) fn ptr_to_vec<T: Copy, U: From<T>>(start: *const T, length: usize) -> Vec<U> {
unsafe { (0..length).map(|i| U::from(*start.offset(i as isize))).collect::<Vec<U>>() }
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem;
#[test]
fn test_addr_size() {
assert_eq!(mem::size_of::<RawAddress>(), mem::size_of::<FfiAddress>());
}
#[test]
fn test_offset() {
let r = RawAddress { val: [1, 2, 3, 4, 5, 6] };
let f = FfiAddress { address: [1, 2, 3, 4, 5, 6] };
assert_eq!(
&f as *const _ as usize - &f.address as *const _ as usize,
&r as *const _ as usize - &r.val as *const _ as usize
);
}
#[test]
fn test_alignment() {
assert_eq!(std::mem::align_of::<RawAddress>(), std::mem::align_of::<FfiAddress>());
}
fn make_bdname_from_slice(slice: &[u8]) -> bindings::bt_bdname_t {
// Length of slice must be less than bd_name max
assert!(slice.len() <= 249);
let mut bdname = bindings::bt_bdname_t { name: [128; 249] };
for (i, v) in slice.iter().enumerate() {
bdname.name[i] = v.clone();
}
bdname
}
#[test]
fn test_bdname_conversions() {
let hello_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79, 0]);
assert_eq!("HELLO".to_string(), String::from(hello_bdname));
let empty_bdname = make_bdname_from_slice(&[0]);
assert_eq!("".to_string(), String::from(empty_bdname));
let no_nullterm_bdname = make_bdname_from_slice(&[72, 69, 76, 76, 79]);
assert_eq!("".to_string(), String::from(no_nullterm_bdname));
let invalid_bdname = make_bdname_from_slice(&[128; 249]);
assert_eq!("".to_string(), String::from(invalid_bdname));
}
#[test]
fn test_ptr_to_vec() {
let arr: [i32; 3] = [1, 2, 3];
let vec: Vec<i32> = ptr_to_vec(arr.as_ptr(), arr.len());
let expected: Vec<i32> = vec![1, 2, 3];
assert_eq!(expected, vec);
}
}