use crate::bindings::root as bindings; use crate::btif::{ptr_to_vec, BluetoothInterface, BtStatus, RawAddress, SupportedProfiles, Uuid}; use crate::profiles::gatt::bindings::{ btgatt_callbacks_t, btgatt_client_callbacks_t, btgatt_client_interface_t, btgatt_interface_t, btgatt_scanner_callbacks_t, btgatt_server_callbacks_t, btgatt_server_interface_t, BleAdvertiserInterface, BleScannerInterface, }; use crate::topstack::get_dispatchers; use crate::utils::LTCheckedPtr; use crate::{ccall, mutcxxcall}; use num_derive::{FromPrimitive, ToPrimitive}; use num_traits::cast::{FromPrimitive, ToPrimitive}; use std::fmt::{Display, Formatter, Result}; use std::sync::{Arc, Mutex}; use topshim_macros::{cb_variant, gen_cxx_extern_trivial}; pub type BtGattNotifyParams = bindings::btgatt_notify_params_t; pub type BtGattReadParams = bindings::btgatt_read_params_t; pub type BtGattDbElement = bindings::btgatt_db_element_t; pub type BtGattResponse = bindings::btgatt_response_t; pub type BtGattValue = bindings::btgatt_value_t; pub type BtGattTestParams = bindings::btgatt_test_params_t; #[cxx::bridge(namespace = bluetooth::topshim::rust)] pub mod ffi { unsafe extern "C++" { include!("types/raw_address.h"); #[namespace = ""] type RawAddress = crate::btif::RawAddress; #[namespace = "bluetooth"] type Uuid = crate::btif::Uuid; } #[derive(Debug, Clone)] pub struct RustAdvertisingTrackInfo { monitor_handle: u8, scanner_id: u8, filter_index: u8, advertiser_state: u8, advertiser_info_present: u8, advertiser_address: RawAddress, advertiser_address_type: u8, tx_power: u8, rssi: i8, timestamp: u16, adv_packet_len: u8, adv_packet: Vec, scan_response_len: u8, scan_response: Vec, } // Defined in C++ and needs a translation in shim. #[derive(Debug, Clone)] pub struct RustApcfCommand { type_: u8, address: RawAddress, addr_type: u8, uuid: Uuid, uuid_mask: Uuid, name: Vec, company: u16, company_mask: u16, ad_type: u8, org_id: u8, tds_flags: u8, tds_flags_mask: u8, meta_data_type: u8, meta_data: Vec, data: Vec, data_mask: Vec, irk: [u8; 16], } // Defined in C++ and needs a translation in shim. #[derive(Debug, Clone)] pub struct RustMsftAdvMonitorPattern { pub ad_type: u8, pub start_byte: u8, pub pattern: Vec, } #[derive(Debug, Clone)] pub struct RustMsftAdvMonitorAddress { pub addr_type: u8, pub bd_addr: RawAddress, } // Defined in C++ and needs a translation in shim. #[derive(Debug, Clone)] pub struct RustMsftAdvMonitor { pub rssi_high_threshold: u8, pub rssi_low_threshold: u8, pub rssi_low_timeout: u8, pub rssi_sampling_period: u8, pub condition_type: u8, pub patterns: Vec, pub addr_info: RustMsftAdvMonitorAddress, } unsafe extern "C++" { include!("gatt/gatt_shim.h"); type GattClientIntf; unsafe fn GetGattClientProfile(btif: *const u8) -> UniquePtr; fn read_phy(self: Pin<&mut GattClientIntf>, client_if: i32, bt_addr: RawAddress) -> i32; type GattServerIntf; unsafe fn GetGattServerProfile(btif: *const u8) -> UniquePtr; fn server_read_phy( self: Pin<&mut GattServerIntf>, server_if: i32, bt_addr: RawAddress, ) -> i32; } extern "Rust" { // Generated by cb_variant! below. fn read_phy_callback(client_if: i32, addr: RawAddress, tx_phy: u8, rx_phy: u8, status: u8); fn server_read_phy_callback( server_if: i32, addr: RawAddress, tx_phy: u8, rx_phy: u8, status: u8, ); } unsafe extern "C++" { include!("gatt/gatt_ble_scanner_shim.h"); type BleScannerIntf; #[namespace = ""] #[cxx_name = "btgatt_filt_param_setup_t"] type GattFilterParam = super::GattFilterParam; unsafe fn GetBleScannerIntf(gatt: *const u8) -> UniquePtr; fn RegisterScanner(self: Pin<&mut BleScannerIntf>, uuid: Uuid); fn Unregister(self: Pin<&mut BleScannerIntf>, scanner_id: u8); fn Scan(self: Pin<&mut BleScannerIntf>, start: bool); fn ScanFilterParamSetup( self: Pin<&mut BleScannerIntf>, scanner_id: u8, action: u8, filter_index: u8, filt_param: GattFilterParam, ); fn ScanFilterAdd( self: Pin<&mut BleScannerIntf>, filter_index: u8, filters: Vec, ); fn ScanFilterClear(self: Pin<&mut BleScannerIntf>, filter_index: u8); fn ScanFilterEnable(self: Pin<&mut BleScannerIntf>, enable: bool); fn IsMsftSupported(self: Pin<&mut BleScannerIntf>) -> bool; fn MsftAdvMonitorAdd( self: Pin<&mut BleScannerIntf>, call_id: u32, monitor: &RustMsftAdvMonitor, ); fn MsftAdvMonitorRemove(self: Pin<&mut BleScannerIntf>, call_id: u32, monitor_handle: u8); fn MsftAdvMonitorEnable(self: Pin<&mut BleScannerIntf>, call_id: u32, enable: bool); fn SetScanParameters( self: Pin<&mut BleScannerIntf>, scanner_id: u8, scan_type: u8, scan_interval: u16, scan_window: u16, scan_phy: u8, ); fn BatchscanConfigStorage( self: Pin<&mut BleScannerIntf>, scanner_id: u8, batch_scan_full_max: i32, batch_scan_trunc_max: i32, batch_scan_notify_threshold: i32, ); fn BatchscanEnable( self: Pin<&mut BleScannerIntf>, scan_mode: i32, scan_interval: u16, scan_window: u16, addr_type: i32, discard_rule: i32, ); fn BatchscanDisable(self: Pin<&mut BleScannerIntf>); fn BatchscanReadReports(self: Pin<&mut BleScannerIntf>, scanner_id: u8, scan_mode: i32); fn StartSync( self: Pin<&mut BleScannerIntf>, sid: u8, address: RawAddress, skip: u16, timeout: u16, ); fn StopSync(self: Pin<&mut BleScannerIntf>, handle: u16); fn CancelCreateSync(self: Pin<&mut BleScannerIntf>, sid: u8, address: RawAddress); fn TransferSync( self: Pin<&mut BleScannerIntf>, address: RawAddress, service_data: u16, sync_handle: u16, ); fn TransferSetInfo( self: Pin<&mut BleScannerIntf>, address: RawAddress, service_data: u16, adv_handle: u8, ); fn SyncTxParameters( self: Pin<&mut BleScannerIntf>, address: RawAddress, mode: u8, skip: u16, timeout: u16, ); /// Registers a C++ |ScanningCallbacks| implementation with the BleScanner. /// The shim implementation will call all the callbacks defined via |cb_variant!|. fn RegisterCallbacks(self: Pin<&mut BleScannerIntf>); } extern "Rust" { // All callbacks below are generated by cb_variant! and will be called // by the ScanningCallbacks handler in shim. unsafe fn gdscan_on_scanner_registered(uuid: *const i8, scannerId: u8, status: u8); unsafe fn gdscan_on_set_scanner_parameter_complete(scannerId: u8, status: u8); unsafe fn gdscan_on_scan_result( event_type: u16, addr_type: u8, addr: *const RawAddress, primary_phy: u8, secondary_phy: u8, advertising_sid: u8, tx_power: i8, rssi: i8, periodic_adv_int: u16, adv_data_ptr: *const u8, adv_data_len: usize, ); unsafe fn gdscan_on_track_adv_found_lost(adv_track_info: RustAdvertisingTrackInfo); unsafe fn gdscan_on_batch_scan_reports( client_if: i32, status: i32, report_format: i32, num_records: i32, data_ptr: *const u8, data_len: usize, ); unsafe fn gdscan_on_batch_scan_threshold_crossed(client_if: i32); // Static cb_variant! callbacks using base::Callback unsafe fn gdscan_register_callback(uuid: Uuid, scanner_id: u8, btm_status: u8); unsafe fn gdscan_status_callback(scanner_id: u8, btm_status: u8); unsafe fn gdscan_enable_callback(action: u8, btm_status: u8); unsafe fn gdscan_filter_param_setup_callback( scanner_id: u8, available_space: u8, action: u8, btm_status: u8, ); unsafe fn gdscan_filter_config_callback( filter_index: u8, filter_type: u8, available_space: u8, action: u8, btm_status: u8, ); unsafe fn gdscan_msft_adv_monitor_add_callback( call_id: u32, monitor_handle: u8, status: u8, ); unsafe fn gdscan_msft_adv_monitor_remove_callback(call_id: u32, status: u8); unsafe fn gdscan_msft_adv_monitor_enable_callback(call_id: u32, status: u8); unsafe fn gdscan_start_sync_callback( status: u8, sync_handle: u16, advertising_sid: u8, addr_type: u8, address: *const RawAddress, phy: u8, interval: u16, ); unsafe fn gdscan_sync_report_callback( sync_handle: u16, tx_power: i8, rssi: i8, status: u8, data: *const u8, len: usize, ); unsafe fn gdscan_sync_lost_callback(sync_handle: u16); unsafe fn gdscan_sync_transfer_callback(status: u8, address: *const RawAddress); unsafe fn gdscan_biginfo_report_callback(sync_handle: u16, encrypted: bool); } unsafe extern "C++" { include!("gatt/gatt_ble_advertiser_shim.h"); type BleAdvertiserIntf; #[namespace = ""] type AdvertiseParameters = super::AdvertiseParameters; #[namespace = ""] type PeriodicAdvertisingParameters = super::PeriodicAdvertisingParameters; /// Given the gatt profile interface, creates a shim interface for /// |BleAdvertiserInterface|. unsafe fn GetBleAdvertiserIntf(gatt: *const u8) -> UniquePtr; fn RegisterAdvertiser(self: Pin<&mut BleAdvertiserIntf>); fn Unregister(self: Pin<&mut BleAdvertiserIntf>, adv_id: u8); fn GetOwnAddress(self: Pin<&mut BleAdvertiserIntf>, adv_id: u8); fn SetParameters( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, params: AdvertiseParameters, ); fn SetData( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, set_scan_rsp: bool, data: Vec, ); fn Enable( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, enable: bool, duration: u16, max_ext_adv_events: u8, ); fn StartAdvertising( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, params: AdvertiseParameters, advertise_data: Vec, scan_response_data: Vec, timeout_in_sec: i32, ); fn StartAdvertisingSet( self: Pin<&mut BleAdvertiserIntf>, reg_id: i32, params: AdvertiseParameters, advertise_data: Vec, scan_response_data: Vec, periodic_params: PeriodicAdvertisingParameters, periodic_data: Vec, duration: u16, max_ext_adv_events: u8, ); fn SetPeriodicAdvertisingParameters( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, params: PeriodicAdvertisingParameters, ); fn SetPeriodicAdvertisingData(self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, data: Vec); fn SetPeriodicAdvertisingEnable( self: Pin<&mut BleAdvertiserIntf>, adv_id: u8, enable: bool, include_adi: bool, ); /// Registers a C++ |AdvertisingCallbacks| implementation with the BleAdvertiser. /// The shim implementation will call all the callbacks defined via |cb_variant!|. fn RegisterCallbacks(self: Pin<&mut BleAdvertiserIntf>); } extern "Rust" { // All callbacks below are generated by cb_variant!. unsafe fn gdadv_on_advertising_set_started( reg_id: i32, adv_id: u8, tx_power: i8, status: u8, ); unsafe fn gdadv_on_advertising_enabled(adv_id: u8, enabled: bool, status: u8); unsafe fn gdadv_on_advertising_data_set(adv_id: u8, status: u8); unsafe fn gdadv_on_scan_response_data_set(adv_id: u8, status: u8); unsafe fn gdadv_on_advertising_parameters_updated(adv_id: u8, tx_power: i8, status: u8); unsafe fn gdadv_on_periodic_advertising_parameters_updated(adv_id: u8, status: u8); unsafe fn gdadv_on_periodic_advertising_data_set(adv_id: u8, status: u8); unsafe fn gdadv_on_periodic_advertising_enabled(adv_id: u8, enabled: bool, status: u8); unsafe fn gdadv_on_own_address_read(adv_id: u8, addr_type: u8, address: *const RawAddress); // In-band callbacks also generated with cb_variant!. unsafe fn gdadv_idstatus_callback(adv_id: u8, status: u8); unsafe fn gdadv_idtxpowerstatus_callback(adv_id: u8, tx_power: i8, status: u8); unsafe fn gdadv_parameters_callback(adv_id: u8, status: u8, tx_power: i8); unsafe fn gdadv_getaddress_callback(adv_id: u8, addr_type: u8, address: *const RawAddress); } } // Non-trivial types, conversion in .cc is necessary. pub type AdvertisingTrackInfo = ffi::RustAdvertisingTrackInfo; pub type ApcfCommand = ffi::RustApcfCommand; pub type MsftAdvMonitor = ffi::RustMsftAdvMonitor; pub type MsftAdvMonitorPattern = ffi::RustMsftAdvMonitorPattern; pub type MsftAdvMonitorAddress = ffi::RustMsftAdvMonitorAddress; #[gen_cxx_extern_trivial] pub type GattFilterParam = bindings::btgatt_filt_param_setup_t; #[gen_cxx_extern_trivial] pub type AdvertiseParameters = bindings::AdvertiseParameters; #[gen_cxx_extern_trivial] pub type PeriodicAdvertisingParameters = bindings::PeriodicAdvertisingParameters; #[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] #[repr(u32)] pub enum GattStatus { Success = 0x00, InvalidHandle = 0x01, ReadNotPermit = 0x02, WriteNotPermit = 0x03, InvalidPdu = 0x04, InsufAuthentication = 0x05, ReqNotSupported = 0x06, InvalidOffset = 0x07, InsufAuthorization = 0x08, PrepareQFull = 0x09, NotFound = 0x0a, NotLong = 0x0b, InsufKeySize = 0x0c, InvalidAttrLen = 0x0d, ErrUnlikely = 0x0e, InsufEncryption = 0x0f, UnsupportGrpType = 0x10, InsufResource = 0x11, DatabaseOutOfSync = 0x12, ValueNotAllowed = 0x13, IllegalParameter = 0x87, TooShort = 0x7f, NoResources = 0x80, InternalError = 0x81, WrongState = 0x82, DbFull = 0x83, Busy = 0x84, Error = 0x85, CmdStarted = 0x86, Pending = 0x88, AuthFail = 0x89, More = 0x8a, InvalidCfg = 0x8b, ServiceStarted = 0x8c, EncryptedNoMitm = 0x8d, NotEncrypted = 0x8e, Congested = 0x8f, DupReg = 0x90, /* 0x90 */ AlreadyOpen = 0x91, /* 0x91 */ Cancel = 0x92, /* 0x92 */ /* = 0xE0 ~ 0xFC reserved for future use */ /* Client Characteristic Configuration Descriptor Improperly Configured */ CccCfgErr = 0xFD, /* Procedure Already in progress */ PrcInProgress = 0xFE, /* Attribute value out of range */ OutOfRange = 0xFF, } impl From for GattStatus { fn from(item: u8) -> Self { match GattStatus::from_u8(item) { Some(s) => s, None => GattStatus::InternalError, } } } impl From for GattStatus { fn from(item: i32) -> Self { if item > 0xff { GattStatus::OutOfRange } else if let Some(s) = GattStatus::from_i32(item) { s } else { GattStatus::InternalError } } } impl Display for GattStatus { fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "{}", self.to_u32().unwrap_or(0)) } } #[derive(Debug, FromPrimitive, ToPrimitive, Clone, Copy)] #[repr(u32)] /// LE Discoverable modes. pub enum LeDiscMode { Invalid = 0, NonDiscoverable, LimitedDiscoverable, GeneralDiscoverable, } impl From for LeDiscMode { fn from(num: u32) -> Self { LeDiscMode::from_u32(num).unwrap_or(LeDiscMode::Invalid) } } impl Into for LeDiscMode { fn into(self) -> u32 { self.to_u32().unwrap_or(0) } } impl Default for LeDiscMode { fn default() -> Self { LeDiscMode::Invalid } } #[derive(Debug, FromPrimitive, ToPrimitive, Clone, Copy)] #[repr(u8)] /// Represents LE PHY. pub enum LePhy { Invalid = 0, Phy1m = 1, Phy2m = 2, PhyCoded = 3, } impl From for i32 { fn from(item: LePhy) -> Self { item.to_i32().unwrap_or(0) } } impl From for u8 { fn from(item: LePhy) -> Self { item.to_u8().unwrap_or(0) } } impl Default for LePhy { fn default() -> Self { LePhy::Invalid } } #[derive(Clone, Copy, Debug, FromPrimitive, ToPrimitive, PartialEq, PartialOrd)] #[repr(u32)] pub enum AdvertisingStatus { Success = 0x0, DataTooLarge = 0x1, TooManyAdvertisers = 0x2, AlreadyStarted = 0x3, InternalError = 0x4, FeatureUnsupported = 0x5, } impl From for AdvertisingStatus { fn from(item: u8) -> Self { match AdvertisingStatus::from_u8(item) { Some(s) => s, None => AdvertisingStatus::InternalError, } } } #[derive(Debug)] pub enum GattClientCallbacks { RegisterClient(GattStatus, i32, Uuid), Connect(i32, GattStatus, i32, RawAddress), Disconnect(i32, GattStatus, i32, RawAddress), SearchComplete(i32, GattStatus), RegisterForNotification(i32, i32, GattStatus, u16), Notify(i32, BtGattNotifyParams), ReadCharacteristic(i32, GattStatus, BtGattReadParams), WriteCharacteristic(i32, GattStatus, u16, u16, *const u8), ReadDescriptor(i32, GattStatus, BtGattReadParams), WriteDescriptor(i32, GattStatus, u16, u16, *const u8), ExecuteWrite(i32, GattStatus), ReadRemoteRssi(i32, RawAddress, i32, GattStatus), ConfigureMtu(i32, GattStatus, i32), Congestion(i32, bool), GetGattDb(i32, Vec, i32), PhyUpdated(i32, u8, u8, GattStatus), ConnUpdated(i32, u16, u16, u16, GattStatus), ServiceChanged(i32), ReadPhy(i32, RawAddress, u8, u8, GattStatus), } #[derive(Debug)] pub enum GattServerCallbacks { RegisterServer(GattStatus, i32, Uuid), Connection(i32, i32, i32, RawAddress), ServiceAdded(GattStatus, i32, Vec, usize), ServiceStopped(GattStatus, i32, i32), ServiceDeleted(GattStatus, i32, i32), RequestReadCharacteristic(i32, i32, RawAddress, i32, i32, bool), RequestReadDescriptor(i32, i32, RawAddress, i32, i32, bool), RequestWriteCharacteristic(i32, i32, RawAddress, i32, i32, bool, bool, Vec, usize), RequestWriteDescriptor(i32, i32, RawAddress, i32, i32, bool, bool, Vec, usize), RequestExecWrite(i32, i32, RawAddress, i32), ResponseConfirmation(i32, i32), IndicationSent(i32, GattStatus), Congestion(i32, bool), MtuChanged(i32, i32), PhyUpdated(i32, u8, u8, GattStatus), ConnUpdated(i32, u16, u16, u16, GattStatus), ReadPhy(i32, RawAddress, u8, u8, GattStatus), SubrateChanged(i32, u16, u16, u16, u16, GattStatus), } pub struct GattClientCallbacksDispatcher { pub dispatch: Box, } pub struct GattServerCallbacksDispatcher { pub dispatch: Box, } type GattClientCb = Arc>; type GattServerCb = Arc>; cb_variant!( GattClientCb, gc_register_client_cb -> GattClientCallbacks::RegisterClient, i32 -> GattStatus, i32, *const Uuid, { let _2 = unsafe { *_2.clone() }; } ); cb_variant!( GattClientCb, gc_open_cb -> GattClientCallbacks::Connect, i32, i32 -> GattStatus, i32, *const RawAddress, { let _3 = unsafe { *_3 }; } ); cb_variant!( GattClientCb, gc_close_cb -> GattClientCallbacks::Disconnect, i32, i32 -> GattStatus, i32, *const RawAddress, { let _3 = unsafe { *_3 }; } ); cb_variant!( GattClientCb, gc_search_complete_cb -> GattClientCallbacks::SearchComplete, i32, i32 -> GattStatus, {} ); cb_variant!( GattClientCb, gc_register_for_notification_cb -> GattClientCallbacks::RegisterForNotification, i32, i32, i32 -> GattStatus, u16, {} ); cb_variant!( GattClientCb, gc_notify_cb -> GattClientCallbacks::Notify, i32, *const BtGattNotifyParams, { let _1 = unsafe { *_1.clone() }; } ); cb_variant!( GattClientCb, gc_read_characteristic_cb -> GattClientCallbacks::ReadCharacteristic, i32, i32 -> GattStatus, *const BtGattReadParams, { let _2 = unsafe { *_2.clone() }; } ); cb_variant!( GattClientCb, gc_write_characteristic_cb -> GattClientCallbacks::WriteCharacteristic, i32, i32 -> GattStatus, u16, u16, *const u8, {} ); cb_variant!( GattClientCb, gc_read_descriptor_cb -> GattClientCallbacks::ReadDescriptor, i32, i32 -> GattStatus, *const BtGattReadParams, { let _2 = unsafe { *_2.clone() }; } ); cb_variant!( GattClientCb, gc_write_descriptor_cb -> GattClientCallbacks::WriteDescriptor, i32, i32 -> GattStatus, u16, u16, *const u8, {} ); cb_variant!( GattClientCb, gc_execute_write_cb -> GattClientCallbacks::ExecuteWrite, i32, i32 -> GattStatus, {} ); cb_variant!( GattClientCb, gc_read_remote_rssi_cb -> GattClientCallbacks::ReadRemoteRssi, i32, *const RawAddress, i32, i32 -> GattStatus, { let _1 = unsafe { *_1 }; } ); cb_variant!( GattClientCb, gc_configure_mtu_cb -> GattClientCallbacks::ConfigureMtu, i32, i32 -> GattStatus, i32, {} ); cb_variant!( GattClientCb, gc_congestion_cb -> GattClientCallbacks::Congestion, i32, bool, {} ); cb_variant!( GattClientCb, gc_get_gatt_db_cb -> GattClientCallbacks::GetGattDb, i32, *const BtGattDbElement, i32, { let _1 = ptr_to_vec(_1, _2 as usize); } ); cb_variant!( GattClientCb, gc_phy_updated_cb -> GattClientCallbacks::PhyUpdated, i32, u8, u8, u8 -> GattStatus, {} ); cb_variant!( GattClientCb, gc_conn_updated_cb -> GattClientCallbacks::ConnUpdated, i32, u16, u16, u16, u8 -> GattStatus, {} ); cb_variant!( GattClientCb, gc_service_changed_cb -> GattClientCallbacks::ServiceChanged, i32, {} ); cb_variant!( GattClientCb, read_phy_callback -> GattClientCallbacks::ReadPhy, i32, RawAddress, u8, u8, u8 -> GattStatus); cb_variant!( GattServerCb, gs_register_server_cb -> GattServerCallbacks::RegisterServer, i32 -> GattStatus, i32, *const Uuid, { let _2 = unsafe { *_2.clone() }; } ); cb_variant!( GattServerCb, gs_connection_cb -> GattServerCallbacks::Connection, i32, i32, i32, *const RawAddress, { let _3 = unsafe { *_3 }; } ); cb_variant!( GattServerCb, gs_service_added_cb -> GattServerCallbacks::ServiceAdded, i32 -> GattStatus, i32, *const BtGattDbElement, usize, { let _2 = ptr_to_vec(_2, _3); } ); cb_variant!( GattServerCb, gs_service_stopped_cb -> GattServerCallbacks::ServiceStopped, i32 -> GattStatus, i32, i32, {} ); cb_variant!( GattServerCb, gs_service_deleted_cb -> GattServerCallbacks::ServiceDeleted, i32 -> GattStatus, i32, i32, {} ); cb_variant!( GattServerCb, gs_request_read_characteristic_cb -> GattServerCallbacks::RequestReadCharacteristic, i32, i32, *const RawAddress, i32, i32, bool, { let _2 = unsafe { *_2 }; } ); cb_variant!( GattServerCb, gs_request_read_descriptor_cb -> GattServerCallbacks::RequestReadDescriptor, i32, i32, *const RawAddress, i32, i32, bool, { let _2 = unsafe { *_2 }; } ); cb_variant!( GattServerCb, gs_request_write_characteristic_cb -> GattServerCallbacks::RequestWriteCharacteristic, i32, i32, *const RawAddress, i32, i32, bool, bool, *const u8, usize, { let _2 = unsafe { *_2 }; let _7 = ptr_to_vec(_7, _8); } ); cb_variant!( GattServerCb, gs_request_write_descriptor_cb -> GattServerCallbacks::RequestWriteDescriptor, i32, i32, *const RawAddress, i32, i32, bool, bool, *const u8, usize, { let _2 = unsafe { *_2 }; let _7 = ptr_to_vec(_7, _8); } ); cb_variant!( GattServerCb, gs_request_exec_write_cb -> GattServerCallbacks::RequestExecWrite, i32, i32, *const RawAddress, i32, { let _2 = unsafe { *_2 }; } ); cb_variant!( GattServerCb, gs_response_confirmation_cb -> GattServerCallbacks::ResponseConfirmation, i32, i32, {} ); cb_variant!( GattServerCb, gs_indication_sent_cb -> GattServerCallbacks::IndicationSent, i32, i32 -> GattStatus, {} ); cb_variant!( GattServerCb, gs_congestion_cb -> GattServerCallbacks::Congestion, i32, bool, {} ); cb_variant!( GattServerCb, gs_mtu_changed_cb -> GattServerCallbacks::MtuChanged, i32, i32, {} ); cb_variant!( GattServerCb, gs_phy_updated_cb -> GattServerCallbacks::PhyUpdated, i32, u8, u8, u8 -> GattStatus, {} ); cb_variant!( GattServerCb, gs_conn_updated_cb -> GattServerCallbacks::ConnUpdated, i32, u16, u16, u16, u8 -> GattStatus, {} ); cb_variant!( GattServerCb, server_read_phy_callback -> GattServerCallbacks::ReadPhy, i32, RawAddress, u8, u8, u8 -> GattStatus); cb_variant!( GattServerCb, gs_subrate_chg_cb -> GattServerCallbacks::SubrateChanged, i32, u16, u16, u16, u16, u8 -> GattStatus, {} ); /// Scanning callbacks used by the GD implementation of BleScannerInterface. /// These callbacks should be registered using |RegisterCallbacks| on /// `BleScannerInterface`. #[derive(Debug)] pub enum GattScannerCallbacks { OnScannerRegistered(Uuid, u8, GattStatus), OnSetScannerParameterComplete(u8, u8), OnScanResult(u16, u8, RawAddress, u8, u8, u8, i8, i8, u16, Vec), OnTrackAdvFoundLost(AdvertisingTrackInfo), OnBatchScanReports(i32, i32, i32, i32, Vec), OnBatchScanThresholdCrossed(i32), } pub struct GattScannerCallbacksDispatcher { pub dispatch: Box, } type GDScannerCb = Arc>; cb_variant!( GDScannerCb, gdscan_on_scanner_registered -> GattScannerCallbacks::OnScannerRegistered, *const i8, u8, u8 -> GattStatus, { let _0 = unsafe { *(_0 as *const Uuid).clone() }; } ); cb_variant!( GDScannerCb, gdscan_on_set_scanner_parameter_complete -> GattScannerCallbacks::OnSetScannerParameterComplete, u8, u8 ); cb_variant!( GDScannerCb, gdscan_on_scan_result -> GattScannerCallbacks::OnScanResult, u16, u8, *const RawAddress, u8, u8, u8, i8, i8, u16, *const u8, usize -> _, { let _2 = unsafe { *_2 }; // Convert the vec! at the end. Since this cb is being called via cxx // ffi, we do the vector separation at the cxx layer. The usize is consumed during // conversion. let _9 : Vec = ptr_to_vec(_9, _10); } ); cb_variant!( GDScannerCb, gdscan_on_track_adv_found_lost -> GattScannerCallbacks::OnTrackAdvFoundLost, AdvertisingTrackInfo); cb_variant!( GDScannerCb, gdscan_on_batch_scan_reports -> GattScannerCallbacks::OnBatchScanReports, i32, i32, i32, i32, *const u8, usize -> _, { // Write the vector to the output and consume the usize in the input. let _4 : Vec = ptr_to_vec(_4, _5); } ); cb_variant!(GDScannerCb, gdscan_on_batch_scan_threshold_crossed -> GattScannerCallbacks::OnBatchScanThresholdCrossed, i32); /// In-band callbacks from the various |BleScannerInterface| methods. Rather than /// store closures for each registered callback, we instead bind and return an /// identifier for the callback instead (such as scanner id or Uuid). #[derive(Debug)] pub enum GattScannerInbandCallbacks { /// Params: App Uuid, Scanner Id, BTM Status RegisterCallback(Uuid, u8, u8), /// Params: Scanner Id, BTM Status StatusCallback(u8, u8), /// Params: Action (enable/disable), BTM Status EnableCallback(u8, u8), /// Params: Scanner Id, Available Space, Action Type, BTM Status FilterParamSetupCallback(u8, u8, u8, u8), /// Params: Filter Index, Filter Type, Available Space, Action, BTM Status FilterConfigCallback(u8, u8, u8, u8, u8), /// Params: Call ID, Monitor Handle, Status MsftAdvMonitorAddCallback(u32, u8, u8), /// Params: Call ID, Status MsftAdvMonitorRemoveCallback(u32, u8), /// Params: Call ID, Status MsftAdvMonitorEnableCallback(u32, u8), /// Params: Status, Sync Handle, Advertising Sid, Address Type, Address, Phy, Interval StartSyncCallback(u8, u16, u8, u8, RawAddress, u8, u16), /// Params: Sync Handle, Tx Power, RSSI, Status, Data SyncReportCallback(u16, i8, i8, u8, Vec), /// Params: Sync Handle SyncLostCallback(u16), /// Params: Status, Address SyncTransferCallback(u8, RawAddress), /// Params: Sync Handle, Encrypted BigInfoReportCallback(u16, bool), } pub struct GattScannerInbandCallbacksDispatcher { pub dispatch: Box, } type GDScannerInbandCb = Arc>; cb_variant!(GDScannerInbandCb, gdscan_register_callback -> GattScannerInbandCallbacks::RegisterCallback, Uuid, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_status_callback -> GattScannerInbandCallbacks::StatusCallback, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_enable_callback -> GattScannerInbandCallbacks::EnableCallback, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_filter_param_setup_callback -> GattScannerInbandCallbacks::FilterParamSetupCallback, u8, u8, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_filter_config_callback -> GattScannerInbandCallbacks::FilterConfigCallback, u8, u8, u8, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_msft_adv_monitor_add_callback -> GattScannerInbandCallbacks::MsftAdvMonitorAddCallback, u32, u8, u8); cb_variant!(GDScannerInbandCb, gdscan_msft_adv_monitor_remove_callback -> GattScannerInbandCallbacks::MsftAdvMonitorRemoveCallback, u32, u8); cb_variant!(GDScannerInbandCb, gdscan_msft_adv_monitor_enable_callback -> GattScannerInbandCallbacks::MsftAdvMonitorEnableCallback, u32, u8); cb_variant!(GDScannerInbandCb, gdscan_start_sync_callback -> GattScannerInbandCallbacks::StartSyncCallback, u8, u16, u8, u8, *const RawAddress, u8, u16, { let _4 = unsafe { *_4 }; }); cb_variant!(GDScannerInbandCb, gdscan_sync_report_callback -> GattScannerInbandCallbacks::SyncReportCallback, u16, i8, i8, u8, *const u8, usize -> _, { let _4 = ptr_to_vec(_4, _5 as usize); }); cb_variant!(GDScannerInbandCb, gdscan_sync_lost_callback -> GattScannerInbandCallbacks::SyncLostCallback, u16); cb_variant!(GDScannerInbandCb, gdscan_sync_transfer_callback -> GattScannerInbandCallbacks::SyncTransferCallback, u8, *const RawAddress, { let _1 = unsafe { *_1 }; }); cb_variant!(GDScannerInbandCb, gdscan_biginfo_report_callback -> GattScannerInbandCallbacks::BigInfoReportCallback, u16, bool); /// Advertising callbacks used by the GD implementation of BleAdvertiserInterface. /// These callbacks should be registered using |RegisterCallbacks| on /// `BleAdvertiser`. #[derive(Debug)] pub enum GattAdvCallbacks { /// Params: Reg Id, Advertiser Id, Tx Power, Status OnAdvertisingSetStarted(i32, u8, i8, AdvertisingStatus), /// Params: Advertiser Id, Enabled, Status OnAdvertisingEnabled(u8, bool, AdvertisingStatus), /// Params: Advertiser Id, Status OnAdvertisingDataSet(u8, AdvertisingStatus), /// Params: Advertiser Id, Status OnScanResponseDataSet(u8, AdvertisingStatus), /// Params: Advertiser Id, Tx Power, Status OnAdvertisingParametersUpdated(u8, i8, AdvertisingStatus), /// Params: Advertiser Id, Status OnPeriodicAdvertisingParametersUpdated(u8, AdvertisingStatus), /// Params: Advertiser Id, Status OnPeriodicAdvertisingDataSet(u8, AdvertisingStatus), /// Params: Advertiser Id, Enabled, Status OnPeriodicAdvertisingEnabled(u8, bool, AdvertisingStatus), /// Params: Advertiser Id, Address Type, Address OnOwnAddressRead(u8, u8, RawAddress), } pub struct GattAdvCallbacksDispatcher { pub dispatch: Box, } type GDAdvCb = Arc>; cb_variant!(GDAdvCb, gdadv_on_advertising_set_started -> GattAdvCallbacks::OnAdvertisingSetStarted, i32, u8, i8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_advertising_enabled -> GattAdvCallbacks::OnAdvertisingEnabled, u8, bool, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_advertising_data_set -> GattAdvCallbacks::OnAdvertisingDataSet, u8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_scan_response_data_set -> GattAdvCallbacks::OnScanResponseDataSet, u8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_advertising_parameters_updated -> GattAdvCallbacks::OnAdvertisingParametersUpdated, u8, i8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_periodic_advertising_parameters_updated -> GattAdvCallbacks::OnPeriodicAdvertisingParametersUpdated, u8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_periodic_advertising_data_set -> GattAdvCallbacks::OnPeriodicAdvertisingDataSet, u8, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_periodic_advertising_enabled -> GattAdvCallbacks::OnPeriodicAdvertisingEnabled, u8, bool, u8 -> AdvertisingStatus); cb_variant!(GDAdvCb, gdadv_on_own_address_read -> GattAdvCallbacks::OnOwnAddressRead, u8, u8, *const RawAddress, { let _2 = unsafe { *_2 }; }); #[derive(Debug)] pub enum GattAdvInbandCallbacks { /// Params: Advertiser Id, Status /// StatusCallback isn't implemented because we always want advertiser id. IdStatusCallback(u8, u8), /// Params: Advertiser Id, Tx Power, Status IdTxPowerStatusCallback(u8, i8, u8), /// Params: Advertiser Id, Status, Tx Power ParametersCallback(u8, u8, i8), /// Params: Advertiser Id, Addr Type, Address GetAddressCallback(u8, u8, RawAddress), } pub struct GattAdvInbandCallbacksDispatcher { pub dispatch: Box, } type GDAdvInbandCb = Arc>; cb_variant!(GDAdvInbandCb, gdadv_idstatus_callback -> GattAdvInbandCallbacks::IdStatusCallback, u8, u8); cb_variant!(GDAdvInbandCb, gdadv_idtxpowerstatus_callback -> GattAdvInbandCallbacks::IdTxPowerStatusCallback, u8, i8, u8); cb_variant!(GDAdvInbandCb, gdadv_parameters_callback -> GattAdvInbandCallbacks::ParametersCallback, u8, u8, i8); cb_variant!(GDAdvInbandCb, gdadv_getaddress_callback -> GattAdvInbandCallbacks::GetAddressCallback, u8, u8, *const RawAddress, { let _2 = unsafe { *_2 }; }); struct RawGattWrapper { raw: *const btgatt_interface_t, } struct RawGattClientWrapper { raw: *const btgatt_client_interface_t, } struct RawGattServerWrapper { raw: *const btgatt_server_interface_t, } struct RawBleScannerWrapper { _raw: *const BleScannerInterface, } struct RawBleAdvertiserWrapper { _raw: *const BleAdvertiserInterface, } // Pointers unsafe due to ownership but this is a static pointer so Send is ok unsafe impl Send for RawGattWrapper {} unsafe impl Send for RawGattClientWrapper {} unsafe impl Send for RawGattServerWrapper {} unsafe impl Send for RawBleScannerWrapper {} unsafe impl Send for RawBleAdvertiserWrapper {} unsafe impl Send for btgatt_callbacks_t {} unsafe impl Send for GattClient {} unsafe impl Send for GattClientCallbacks {} unsafe impl Send for GattServer {} unsafe impl Send for BleScanner {} unsafe impl Send for BleAdvertiser {} pub struct GattClient { internal: RawGattClientWrapper, internal_cxx: cxx::UniquePtr, } impl GattClient { pub fn register_client(&self, uuid: &Uuid, eatt_support: bool) -> BtStatus { BtStatus::from(ccall!(self, register_client, uuid, eatt_support)) } pub fn unregister_client(&self, client_if: i32) -> BtStatus { BtStatus::from(ccall!(self, unregister_client, client_if)) } pub fn connect( &self, client_if: i32, addr: &RawAddress, addr_type: u8, is_direct: bool, transport: i32, opportunistic: bool, initiating_phys: i32, ) -> BtStatus { BtStatus::from(ccall!( self, connect, client_if, addr, addr_type, is_direct, transport, opportunistic, initiating_phys )) } pub fn disconnect(&self, client_if: i32, addr: &RawAddress, conn_id: i32) -> BtStatus { BtStatus::from(ccall!(self, disconnect, client_if, addr, conn_id)) } pub fn refresh(&self, client_if: i32, addr: &RawAddress) -> BtStatus { BtStatus::from(ccall!(self, refresh, client_if, addr)) } pub fn search_service(&self, conn_id: i32, filter_uuid: Option) -> BtStatus { let filter_uuid_ptr = LTCheckedPtr::from(&filter_uuid); BtStatus::from(ccall!(self, search_service, conn_id, filter_uuid_ptr.into())) } pub fn btif_gattc_discover_service_by_uuid(&self, conn_id: i32, uuid: &Uuid) { ccall!(self, btif_gattc_discover_service_by_uuid, conn_id, uuid) } pub fn read_characteristic(&self, conn_id: i32, handle: u16, auth_req: i32) -> BtStatus { BtStatus::from(ccall!(self, read_characteristic, conn_id, handle, auth_req)) } pub fn read_using_characteristic_uuid( &self, conn_id: i32, uuid: &Uuid, s_handle: u16, e_handle: u16, auth_req: i32, ) -> BtStatus { BtStatus::from(ccall!( self, read_using_characteristic_uuid, conn_id, uuid, s_handle, e_handle, auth_req )) } pub fn write_characteristic( &self, conn_id: i32, handle: u16, write_type: i32, auth_req: i32, value: &[u8], ) -> BtStatus { let value_ptr = LTCheckedPtr::from(value); BtStatus::from(ccall!( self, write_characteristic, conn_id, handle, write_type, auth_req, value_ptr.into(), value.len() )) } pub fn read_descriptor(&self, conn_id: i32, handle: u16, auth_req: i32) -> BtStatus { BtStatus::from(ccall!(self, read_descriptor, conn_id, handle, auth_req)) } pub fn write_descriptor( &self, conn_id: i32, handle: u16, auth_req: i32, value: &[u8], ) -> BtStatus { let value_ptr = LTCheckedPtr::from(value); BtStatus::from(ccall!( self, write_descriptor, conn_id, handle, auth_req, value_ptr.into(), value.len() )) } pub fn execute_write(&self, conn_id: i32, execute: i32) -> BtStatus { BtStatus::from(ccall!(self, execute_write, conn_id, execute)) } pub fn register_for_notification( &self, client_if: i32, addr: &RawAddress, handle: u16, ) -> BtStatus { BtStatus::from(ccall!(self, register_for_notification, client_if, addr, handle)) } pub fn deregister_for_notification( &self, client_if: i32, addr: &RawAddress, handle: u16, ) -> BtStatus { BtStatus::from(ccall!(self, deregister_for_notification, client_if, addr, handle)) } pub fn read_remote_rssi(&self, client_if: i32, addr: &RawAddress) -> BtStatus { BtStatus::from(ccall!(self, read_remote_rssi, client_if, addr)) } pub fn get_device_type(&self, addr: &RawAddress) -> i32 { ccall!(self, get_device_type, addr) } pub fn configure_mtu(&self, conn_id: i32, mtu: i32) -> BtStatus { BtStatus::from(ccall!(self, configure_mtu, conn_id, mtu)) } pub fn conn_parameter_update( &self, addr: &RawAddress, min_interval: i32, max_interval: i32, latency: i32, timeout: i32, min_ce_len: u16, max_ce_len: u16, ) -> BtStatus { BtStatus::from(ccall!( self, conn_parameter_update, addr, min_interval, max_interval, latency, timeout, min_ce_len, max_ce_len )) } pub fn set_preferred_phy( &self, addr: &RawAddress, tx_phy: u8, rx_phy: u8, phy_options: u16, ) -> BtStatus { BtStatus::from(ccall!(self, set_preferred_phy, addr, tx_phy, rx_phy, phy_options)) } pub fn read_phy(&mut self, client_if: i32, addr: &RawAddress) -> BtStatus { BtStatus::from_i32(mutcxxcall!(self, read_phy, client_if, *addr)).unwrap() } pub fn test_command(&self, command: i32, params: &BtGattTestParams) -> BtStatus { BtStatus::from(ccall!(self, test_command, command, params)) } pub fn get_gatt_db(&self, conn_id: i32) -> BtStatus { BtStatus::from(ccall!(self, get_gatt_db, conn_id)) } } pub struct GattServer { internal: RawGattServerWrapper, internal_cxx: cxx::UniquePtr, } impl GattServer { pub fn register_server(&self, uuid: &Uuid, eatt_support: bool) -> BtStatus { BtStatus::from(ccall!(self, register_server, uuid, eatt_support)) } pub fn unregister_server(&self, server_if: i32) -> BtStatus { BtStatus::from(ccall!(self, unregister_server, server_if)) } pub fn connect( &self, server_if: i32, addr: &RawAddress, addr_type: u8, is_direct: bool, transport: i32, ) -> BtStatus { BtStatus::from(ccall!(self, connect, server_if, addr, addr_type, is_direct, transport)) } pub fn disconnect(&self, server_if: i32, addr: &RawAddress, conn_id: i32) -> BtStatus { BtStatus::from(ccall!(self, disconnect, server_if, addr, conn_id)) } pub fn add_service(&self, server_if: i32, service: &[BtGattDbElement]) -> BtStatus { let service_ptr = LTCheckedPtr::from(service); BtStatus::from(ccall!(self, add_service, server_if, service_ptr.into(), service.len())) } pub fn stop_service(&self, server_if: i32, service_handle: i32) -> BtStatus { BtStatus::from(ccall!(self, stop_service, server_if, service_handle)) } pub fn delete_service(&self, server_if: i32, service_handle: i32) -> BtStatus { BtStatus::from(ccall!(self, delete_service, server_if, service_handle)) } pub fn send_indication( &self, server_if: i32, attribute_handle: i32, conn_id: i32, confirm: i32, value: &[u8], ) -> BtStatus { let value_ptr = LTCheckedPtr::from(value); BtStatus::from(ccall!( self, send_indication, server_if, attribute_handle, conn_id, confirm, value_ptr.into(), value.len() )) } pub fn send_response( &self, conn_id: i32, trans_id: i32, status: i32, response: &BtGattResponse, ) -> BtStatus { BtStatus::from(ccall!(self, send_response, conn_id, trans_id, status, response)) } pub fn set_preferred_phy( &self, addr: &RawAddress, tx_phy: u8, rx_phy: u8, phy_options: u16, ) -> BtStatus { BtStatus::from(ccall!(self, set_preferred_phy, addr, tx_phy, rx_phy, phy_options)) } pub fn read_phy(&mut self, server_if: i32, addr: &RawAddress) -> BtStatus { BtStatus::from_i32(mutcxxcall!(self, server_read_phy, server_if, *addr)).unwrap() } } pub struct BleScanner { _internal: RawBleScannerWrapper, internal_cxx: cxx::UniquePtr, } impl BleScanner { pub(crate) fn new( raw_gatt: *const btgatt_interface_t, internal_cxx: cxx::UniquePtr, ) -> Self { BleScanner { _internal: RawBleScannerWrapper { _raw: unsafe { (*raw_gatt).scanner as *const BleScannerInterface }, }, internal_cxx, } } pub fn register_scanner(&mut self, app_uuid: Uuid) { mutcxxcall!(self, RegisterScanner, app_uuid.into()); } pub fn unregister(&mut self, scanner_id: u8) { mutcxxcall!(self, Unregister, scanner_id); } // TODO(b/233124021): topshim should expose scan(enable) instead of start_scan and stop_scan. pub fn start_scan(&mut self) { mutcxxcall!(self, Scan, true); } pub fn stop_scan(&mut self) { mutcxxcall!(self, Scan, false); } pub fn scan_filter_setup( &mut self, scanner_id: u8, action: u8, filter_index: u8, param: GattFilterParam, ) { mutcxxcall!(self, ScanFilterParamSetup, scanner_id, action, filter_index, param); } pub fn scan_filter_add(&mut self, filter_index: u8, filters: Vec) { mutcxxcall!(self, ScanFilterAdd, filter_index, filters); } pub fn scan_filter_clear(&mut self, filter_index: u8) { mutcxxcall!(self, ScanFilterClear, filter_index); } pub fn scan_filter_enable(&mut self) { mutcxxcall!(self, ScanFilterEnable, true); } pub fn scan_filter_disable(&mut self) { mutcxxcall!(self, ScanFilterEnable, false); } pub fn is_msft_supported(&mut self) -> bool { mutcxxcall!(self, IsMsftSupported) } pub fn msft_adv_monitor_add(&mut self, call_id: u32, monitor: &MsftAdvMonitor) { mutcxxcall!(self, MsftAdvMonitorAdd, call_id, monitor); } pub fn msft_adv_monitor_remove(&mut self, call_id: u32, monitor_handle: u8) { mutcxxcall!(self, MsftAdvMonitorRemove, call_id, monitor_handle); } pub fn msft_adv_monitor_enable(&mut self, call_id: u32, enable: bool) { mutcxxcall!(self, MsftAdvMonitorEnable, call_id, enable); } pub fn set_scan_parameters( &mut self, scanner_id: u8, scan_type: u8, scan_interval: u16, scan_window: u16, scan_phy: u8, ) { mutcxxcall!( self, SetScanParameters, scanner_id, scan_type, scan_interval, scan_window, scan_phy ); } pub fn batchscan_config_storage( &mut self, scanner_id: u8, full_max: i32, trunc_max: i32, notify_threshold: i32, ) { mutcxxcall!( self, BatchscanConfigStorage, scanner_id, full_max, trunc_max, notify_threshold ); } pub fn batchscan_enable( &mut self, scan_mode: i32, scan_interval: u16, scan_window: u16, addr_type: i32, discard_rule: i32, ) { mutcxxcall!( self, BatchscanEnable, scan_mode, scan_interval, scan_window, addr_type, discard_rule ); } pub fn batchscan_disable(&mut self) { mutcxxcall!(self, BatchscanDisable); } pub fn batchscan_read_reports(&mut self, scanner_id: u8, scan_mode: i32) { mutcxxcall!(self, BatchscanReadReports, scanner_id, scan_mode); } pub fn start_sync(&mut self, sid: u8, addr: RawAddress, skip: u16, timeout: u16) { mutcxxcall!(self, StartSync, sid, addr, skip, timeout); } pub fn stop_sync(&mut self, handle: u16) { mutcxxcall!(self, StopSync, handle); } pub fn cancel_create_sync(&mut self, sid: u8, addr: RawAddress) { mutcxxcall!(self, CancelCreateSync, sid, addr); } pub fn transfer_sync(&mut self, addr: RawAddress, service_data: u16, sync_handle: u16) { mutcxxcall!(self, TransferSync, addr, service_data, sync_handle); } pub fn transfer_set_info(&mut self, addr: RawAddress, service_data: u16, adv_handle: u8) { mutcxxcall!(self, TransferSetInfo, addr, service_data, adv_handle); } pub fn sync_tx_parameters(&mut self, addr: RawAddress, mode: u8, skip: u16, timeout: u16) { mutcxxcall!(self, SyncTxParameters, addr, mode, skip, timeout); } } pub struct BleAdvertiser { _internal: RawBleAdvertiserWrapper, internal_cxx: cxx::UniquePtr, } impl BleAdvertiser { pub(crate) fn new( raw_gatt: *const btgatt_interface_t, internal_cxx: cxx::UniquePtr, ) -> Self { BleAdvertiser { _internal: RawBleAdvertiserWrapper { _raw: unsafe { (*raw_gatt).advertiser as *const BleAdvertiserInterface }, }, internal_cxx, } } pub fn register_advertiser(&mut self) { mutcxxcall!(self, RegisterAdvertiser); } pub fn unregister(&mut self, adv_id: u8) { mutcxxcall!(self, Unregister, adv_id); } pub fn get_own_address(&mut self, adv_id: u8) { mutcxxcall!(self, GetOwnAddress, adv_id); } pub fn set_parameters(&mut self, adv_id: u8, params: AdvertiseParameters) { mutcxxcall!(self, SetParameters, adv_id, params); } pub fn set_data(&mut self, adv_id: u8, set_scan_rsp: bool, data: Vec) { mutcxxcall!(self, SetData, adv_id, set_scan_rsp, data); } pub fn enable(&mut self, adv_id: u8, enable: bool, duration: u16, max_ext_adv_events: u8) { mutcxxcall!(self, Enable, adv_id, enable, duration, max_ext_adv_events); } pub fn start_advertising( &mut self, adv_id: u8, params: AdvertiseParameters, advertise_data: Vec, scan_response_data: Vec, timeout_in_sec: i32, ) { mutcxxcall!( self, StartAdvertising, adv_id, params, advertise_data, scan_response_data, timeout_in_sec ); } pub fn start_advertising_set( &mut self, reg_id: i32, params: AdvertiseParameters, advertise_data: Vec, scan_response_data: Vec, periodic_params: PeriodicAdvertisingParameters, periodic_data: Vec, duration: u16, max_ext_adv_events: u8, ) { mutcxxcall!( self, StartAdvertisingSet, reg_id, params, advertise_data, scan_response_data, periodic_params, periodic_data, duration, max_ext_adv_events ); } pub fn set_periodic_advertising_parameters( &mut self, adv_id: u8, params: PeriodicAdvertisingParameters, ) { mutcxxcall!(self, SetPeriodicAdvertisingParameters, adv_id, params); } pub fn set_periodic_advertising_data(&mut self, adv_id: u8, data: Vec) { mutcxxcall!(self, SetPeriodicAdvertisingData, adv_id, data); } pub fn set_periodic_advertising_enable(&mut self, adv_id: u8, enable: bool, include_adi: bool) { mutcxxcall!(self, SetPeriodicAdvertisingEnable, adv_id, enable, include_adi); } } pub struct Gatt { internal: RawGattWrapper, is_init: bool, pub client: GattClient, pub server: GattServer, pub scanner: BleScanner, pub advertiser: BleAdvertiser, // Keep callback object in memory (underlying code doesn't make copy) callbacks: Option>, gatt_client_callbacks: Option>, gatt_server_callbacks: Option>, gatt_scanner_callbacks: Option>, } impl Gatt { pub fn new(intf: &BluetoothInterface) -> Option { let r = intf.get_profile_interface(SupportedProfiles::Gatt); if r == std::ptr::null() { return None; } let gatt_client_intf = unsafe { ffi::GetGattClientProfile(r as *const u8) }; let gatt_server_intf = unsafe { ffi::GetGattServerProfile(r as *const u8) }; let gatt_scanner_intf = unsafe { ffi::GetBleScannerIntf(r as *const u8) }; let gatt_advertiser_intf = unsafe { ffi::GetBleAdvertiserIntf(r as *const u8) }; Some(Gatt { internal: RawGattWrapper { raw: r as *const btgatt_interface_t }, is_init: false, client: GattClient { internal: RawGattClientWrapper { raw: unsafe { (*(r as *const btgatt_interface_t)).client as *const btgatt_client_interface_t }, }, internal_cxx: gatt_client_intf, }, server: GattServer { internal: RawGattServerWrapper { raw: unsafe { (*(r as *const btgatt_interface_t)).server as *const btgatt_server_interface_t }, }, internal_cxx: gatt_server_intf, }, scanner: BleScanner::new(r as *const btgatt_interface_t, gatt_scanner_intf), advertiser: BleAdvertiser::new(r as *const btgatt_interface_t, gatt_advertiser_intf), callbacks: None, gatt_client_callbacks: None, gatt_server_callbacks: None, gatt_scanner_callbacks: None, }) } pub fn is_initialized(&self) -> bool { self.is_init } pub fn initialize( &mut self, gatt_client_callbacks_dispatcher: GattClientCallbacksDispatcher, gatt_server_callbacks_dispatcher: GattServerCallbacksDispatcher, gatt_scanner_callbacks_dispatcher: GattScannerCallbacksDispatcher, gatt_scanner_inband_callbacks_dispatcher: GattScannerInbandCallbacksDispatcher, gatt_adv_inband_callbacks_dispatcher: GattAdvInbandCallbacksDispatcher, gatt_adv_callbacks_dispatcher: GattAdvCallbacksDispatcher, ) -> bool { // Register dispatcher if get_dispatchers() .lock() .unwrap() .set::(Arc::new(Mutex::new(gatt_client_callbacks_dispatcher))) { panic!("Tried to set dispatcher for GattClientCallbacks but it already existed"); } if get_dispatchers() .lock() .unwrap() .set::(Arc::new(Mutex::new(gatt_server_callbacks_dispatcher))) { panic!("Tried to set dispatcher for GattServerCallbacks but it already existed"); } if get_dispatchers() .lock() .unwrap() .set::(Arc::new(Mutex::new(gatt_scanner_callbacks_dispatcher))) { panic!("Tried to set dispatcher for GattScannerCallbacks but it already existed"); } if get_dispatchers().lock().unwrap().set::(Arc::new(Mutex::new( gatt_scanner_inband_callbacks_dispatcher, ))) { panic!("Tried to set dispatcher for GattScannerInbandCallbacks but it already existed"); } if get_dispatchers() .lock() .unwrap() .set::(Arc::new(Mutex::new(gatt_adv_inband_callbacks_dispatcher))) { panic!("Tried to set dispatcher for GattAdvInbandCallbacks but it already existed"); } if get_dispatchers() .lock() .unwrap() .set::(Arc::new(Mutex::new(gatt_adv_callbacks_dispatcher))) { panic!("Tried to set dispatcher for GattAdvCallbacks but it already existed"); } let gatt_client_callbacks = Box::new(btgatt_client_callbacks_t { register_client_cb: Some(gc_register_client_cb), open_cb: Some(gc_open_cb), close_cb: Some(gc_close_cb), search_complete_cb: Some(gc_search_complete_cb), register_for_notification_cb: Some(gc_register_for_notification_cb), notify_cb: Some(gc_notify_cb), read_characteristic_cb: Some(gc_read_characteristic_cb), write_characteristic_cb: Some(gc_write_characteristic_cb), read_descriptor_cb: Some(gc_read_descriptor_cb), write_descriptor_cb: Some(gc_write_descriptor_cb), execute_write_cb: Some(gc_execute_write_cb), read_remote_rssi_cb: Some(gc_read_remote_rssi_cb), configure_mtu_cb: Some(gc_configure_mtu_cb), congestion_cb: Some(gc_congestion_cb), get_gatt_db_cb: Some(gc_get_gatt_db_cb), phy_updated_cb: Some(gc_phy_updated_cb), conn_updated_cb: Some(gc_conn_updated_cb), service_changed_cb: Some(gc_service_changed_cb), // These callbacks are never used and will also be removed from btif. // TODO(b/200073464): Remove these. services_removed_cb: None, services_added_cb: None, subrate_chg_cb: None, }); let gatt_server_callbacks = Box::new(btgatt_server_callbacks_t { register_server_cb: Some(gs_register_server_cb), connection_cb: Some(gs_connection_cb), service_added_cb: Some(gs_service_added_cb), service_stopped_cb: Some(gs_service_stopped_cb), service_deleted_cb: Some(gs_service_deleted_cb), request_read_characteristic_cb: Some(gs_request_read_characteristic_cb), request_read_descriptor_cb: Some(gs_request_read_descriptor_cb), request_write_characteristic_cb: Some(gs_request_write_characteristic_cb), request_write_descriptor_cb: Some(gs_request_write_descriptor_cb), request_exec_write_cb: Some(gs_request_exec_write_cb), response_confirmation_cb: Some(gs_response_confirmation_cb), indication_sent_cb: Some(gs_indication_sent_cb), congestion_cb: Some(gs_congestion_cb), mtu_changed_cb: Some(gs_mtu_changed_cb), phy_updated_cb: Some(gs_phy_updated_cb), conn_updated_cb: Some(gs_conn_updated_cb), subrate_chg_cb: Some(gs_subrate_chg_cb), }); let gatt_scanner_callbacks = Box::new(btgatt_scanner_callbacks_t { scan_result_cb: None, batchscan_reports_cb: None, batchscan_threshold_cb: None, track_adv_event_cb: None, }); let callbacks = Box::new(btgatt_callbacks_t { size: std::mem::size_of::(), client: &*gatt_client_callbacks, server: &*gatt_server_callbacks, scanner: &*gatt_scanner_callbacks, }); let cb_ptr = LTCheckedPtr::from(&callbacks); let init = ccall!(self, init, cb_ptr.into()); self.is_init = init == 0; self.callbacks = Some(callbacks); self.gatt_client_callbacks = Some(gatt_client_callbacks); self.gatt_server_callbacks = Some(gatt_server_callbacks); self.gatt_scanner_callbacks = Some(gatt_scanner_callbacks); // Register callbacks for gatt scanner and advertiser mutcxxcall!(self.scanner, RegisterCallbacks); mutcxxcall!(self.advertiser, RegisterCallbacks); return self.is_init; } }