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