1 use crate::btif::{BluetoothInterface, RawAddress, ToggleableProfile, Uuid}; 2 use crate::topstack::get_dispatchers; 3 4 use std::sync::{Arc, Mutex}; 5 use topshim_macros::{cb_variant, profile_enabled_or}; 6 7 use log::warn; 8 9 #[cxx::bridge(namespace = bluetooth::topshim::rust)] 10 pub mod ffi { 11 unsafe extern "C++" { 12 include!("types/raw_address.h"); 13 include!("types/bluetooth/uuid.h"); 14 #[namespace = ""] 15 type RawAddress = crate::btif::RawAddress; 16 #[namespace = "bluetooth"] 17 type Uuid = crate::btif::Uuid; 18 } 19 20 #[derive(Debug, Copy, Clone)] 21 pub enum BtCsisConnectionState { 22 Disconnected = 0, 23 Connecting, 24 Connected, 25 Disconnecting, 26 } 27 28 #[derive(Debug, Copy, Clone)] 29 pub enum BtCsisGroupLockStatus { 30 Success = 0, 31 FailedInvalidGroup, 32 FailedGroupEmpty, 33 FailedGroupNotConnected, 34 FailedLockedByOther, 35 FailedOtherReason, 36 LockedGroupMemberLost, 37 } 38 39 unsafe extern "C++" { 40 include!("csis/csis_shim.h"); 41 42 type CsisClientIntf; 43 GetCsisClientProfile(btif: *const u8) -> UniquePtr<CsisClientIntf>44 unsafe fn GetCsisClientProfile(btif: *const u8) -> UniquePtr<CsisClientIntf>; 45 init(self: Pin<&mut CsisClientIntf>)46 fn init(self: Pin<&mut CsisClientIntf>); connect(self: Pin<&mut CsisClientIntf>, addr: RawAddress)47 fn connect(self: Pin<&mut CsisClientIntf>, addr: RawAddress); disconnect(self: Pin<&mut CsisClientIntf>, addr: RawAddress)48 fn disconnect(self: Pin<&mut CsisClientIntf>, addr: RawAddress); lock_group(self: Pin<&mut CsisClientIntf>, group_id: i32, lock: bool)49 fn lock_group(self: Pin<&mut CsisClientIntf>, group_id: i32, lock: bool); remove_device(self: Pin<&mut CsisClientIntf>, addr: RawAddress)50 fn remove_device(self: Pin<&mut CsisClientIntf>, addr: RawAddress); cleanup(self: Pin<&mut CsisClientIntf>)51 fn cleanup(self: Pin<&mut CsisClientIntf>); 52 } 53 54 extern "Rust" { csis_connection_state_callback(addr: RawAddress, state: BtCsisConnectionState)55 fn csis_connection_state_callback(addr: RawAddress, state: BtCsisConnectionState); csis_device_available_callback( addr: RawAddress, group_id: i32, group_size: i32, rank: i32, uuid: Uuid, )56 fn csis_device_available_callback( 57 addr: RawAddress, 58 group_id: i32, 59 group_size: i32, 60 rank: i32, 61 uuid: Uuid, 62 ); csis_set_member_available_callback(addr: RawAddress, group_id: i32)63 fn csis_set_member_available_callback(addr: RawAddress, group_id: i32); csis_group_lock_changed_callback( group_id: i32, locked: bool, status: BtCsisGroupLockStatus, )64 fn csis_group_lock_changed_callback( 65 group_id: i32, 66 locked: bool, 67 status: BtCsisGroupLockStatus, 68 ); 69 } 70 } 71 72 pub type BtCsisConnectionState = ffi::BtCsisConnectionState; 73 pub type BtCsisGroupLockStatus = ffi::BtCsisGroupLockStatus; 74 75 #[derive(Debug)] 76 pub enum CsisClientCallbacks { 77 ConnectionState(RawAddress, BtCsisConnectionState), 78 DeviceAvailable(RawAddress, i32, i32, i32, Uuid), 79 SetMemberAvailable(RawAddress, i32), 80 GroupLockChanged(i32, bool, BtCsisGroupLockStatus), 81 } 82 83 pub struct CsisClientCallbacksDispatcher { 84 pub dispatch: Box<dyn Fn(CsisClientCallbacks) + Send>, 85 } 86 87 type CsisClientCb = Arc<Mutex<CsisClientCallbacksDispatcher>>; 88 89 cb_variant!(CsisClientCb, 90 csis_connection_state_callback -> CsisClientCallbacks::ConnectionState, 91 RawAddress, BtCsisConnectionState); 92 93 cb_variant!(CsisClientCb, 94 csis_device_available_callback -> CsisClientCallbacks::DeviceAvailable, 95 RawAddress, i32, i32, i32, Uuid); 96 97 cb_variant!(CsisClientCb, 98 csis_set_member_available_callback -> CsisClientCallbacks::SetMemberAvailable, 99 RawAddress, i32); 100 101 cb_variant!(CsisClientCb, 102 csis_group_lock_changed_callback -> CsisClientCallbacks::GroupLockChanged, 103 i32, bool, BtCsisGroupLockStatus); 104 105 pub struct CsisClient { 106 internal: cxx::UniquePtr<ffi::CsisClientIntf>, 107 is_init: bool, 108 is_enabled: bool, 109 } 110 111 // For *const u8 opaque btif 112 // SAFETY: `CsisClientIntf` is thread-safe to make calls from. 113 unsafe impl Send for CsisClient {} 114 115 impl ToggleableProfile for CsisClient { is_enabled(&self) -> bool116 fn is_enabled(&self) -> bool { 117 self.is_enabled 118 } 119 enable(&mut self) -> bool120 fn enable(&mut self) -> bool { 121 if self.is_enabled { 122 warn!("CsisClient is already enabled."); 123 return false; 124 } 125 126 self.internal.pin_mut().init(); 127 self.is_enabled = true; 128 true 129 } 130 131 #[profile_enabled_or(false)] disable(&mut self) -> bool132 fn disable(&mut self) -> bool { 133 if !self.is_enabled { 134 warn!("CsisClient is already disabled."); 135 return false; 136 } 137 138 self.internal.pin_mut().cleanup(); 139 self.is_enabled = false; 140 true 141 } 142 } 143 144 impl CsisClient { new(intf: &BluetoothInterface) -> CsisClient145 pub fn new(intf: &BluetoothInterface) -> CsisClient { 146 let csis_if: cxx::UniquePtr<ffi::CsisClientIntf>; 147 148 // SAFETY: `intf.as_raw_ptr()` is a valid pointer to a `BluetoothInterface` 149 csis_if = unsafe { ffi::GetCsisClientProfile(intf.as_raw_ptr()) }; 150 151 CsisClient { internal: csis_if, is_init: false, is_enabled: false } 152 } 153 is_initialized(&self) -> bool154 pub fn is_initialized(&self) -> bool { 155 self.is_init 156 } 157 158 // `internal.init` is invoked during `ToggleableProfile::enable` initialize(&mut self, callbacks: CsisClientCallbacksDispatcher) -> bool159 pub fn initialize(&mut self, callbacks: CsisClientCallbacksDispatcher) -> bool { 160 if self.is_init { 161 warn!("CsisClient has already been initialized"); 162 return false; 163 } 164 165 if get_dispatchers().lock().unwrap().set::<CsisClientCb>(Arc::new(Mutex::new(callbacks))) { 166 panic!("Tried to set dispatcher for CsisClient callbacks while it already exists"); 167 } 168 169 self.is_init = true; 170 171 true 172 } 173 174 #[profile_enabled_or] cleanup(&mut self)175 pub fn cleanup(&mut self) { 176 self.internal.pin_mut().cleanup(); 177 } 178 179 #[profile_enabled_or] connect(&mut self, addr: RawAddress)180 pub fn connect(&mut self, addr: RawAddress) { 181 self.internal.pin_mut().connect(addr); 182 } 183 184 #[profile_enabled_or] disconnect(&mut self, addr: RawAddress)185 pub fn disconnect(&mut self, addr: RawAddress) { 186 self.internal.pin_mut().disconnect(addr); 187 } 188 189 #[profile_enabled_or] lock_group(&mut self, group_id: i32, lock: bool)190 pub fn lock_group(&mut self, group_id: i32, lock: bool) { 191 self.internal.pin_mut().lock_group(group_id, lock); 192 } 193 194 #[profile_enabled_or] remove_device(&mut self, addr: RawAddress)195 pub fn remove_device(&mut self, addr: RawAddress) { 196 self.internal.pin_mut().remove_device(addr); 197 } 198 } 199