| use crate::bindings::root as bindings; |
| use crate::btif::{ |
| ptr_to_vec, BluetoothInterface, BtStatus, FfiAddress, 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::{cast_to_ffi_address, ccall, deref_ffi_address}; |
| |
| use num_traits::cast::FromPrimitive; |
| |
| use std::sync::{Arc, Mutex}; |
| |
| use topshim_macros::cb_variant; |
| |
| 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 BtGattTestParams = bindings::btgatt_test_params_t; |
| |
| #[cxx::bridge(namespace = bluetooth::topshim::rust)] |
| pub mod ffi { |
| #[derive(Debug, Copy, Clone)] |
| pub struct RustRawAddress { |
| address: [u8; 6], |
| } |
| |
| unsafe extern "C++" { |
| include!("gatt/gatt_shim.h"); |
| |
| type GattClientIntf; |
| |
| unsafe fn GetGattClientProfile(btif: *const u8) -> UniquePtr<GattClientIntf>; |
| |
| fn read_phy(self: Pin<&mut GattClientIntf>, client_if: i32, bt_addr: RustRawAddress) |
| -> i32; |
| } |
| |
| extern "Rust" { |
| // Generated by cb_variant! below. |
| fn read_phy_callback( |
| client_if: i32, |
| addr: RustRawAddress, |
| tx_phy: u8, |
| rx_phy: u8, |
| status: u8, |
| ); |
| } |
| } |
| |
| #[derive(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, |
| } |
| |
| #[derive(Debug)] |
| pub enum GattClientCallbacks { |
| RegisterClient(i32, i32, Uuid), |
| Connect(i32, i32, i32, RawAddress), |
| Disconnect(i32, i32, i32, RawAddress), |
| SearchComplete(i32, i32), |
| RegisterForNotification(i32, i32, i32, u16), |
| Notify(i32, BtGattNotifyParams), |
| ReadCharacteristic(i32, i32, BtGattReadParams), |
| WriteCharacteristic(i32, i32, u16, u16, *const u8), |
| ReadDescriptor(i32, i32, BtGattReadParams), |
| WriteDescriptor(i32, i32, u16, u16, *const u8), |
| ExecuteWrite(i32, i32), |
| ReadRemoteRssi(i32, RawAddress, i32, i32), |
| ConfigureMtu(i32, i32, i32), |
| Congestion(i32, bool), |
| GetGattDb(i32, Vec<BtGattDbElement>, i32), |
| PhyUpdated(i32, u8, u8, u8), |
| ConnUpdated(i32, u16, u16, u16, u8), |
| ServiceChanged(i32), |
| ReadPhy(i32, RawAddress, u8, u8, u8), |
| } |
| |
| #[derive(Debug)] |
| pub enum GattServerCallbacks { |
| RegisterServer(i32, i32, Uuid), |
| Connection(i32, i32, i32, RawAddress), |
| ServiceAdded(i32, i32, Vec<BtGattDbElement>, usize), |
| ServiceStopped(i32, i32, i32), |
| ServiceDeleted(i32, 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<u8>, usize), |
| RequestWriteDescriptor(i32, i32, RawAddress, i32, i32, bool, bool, Vec<u8>, usize), |
| RequestExecWrite(i32, i32, RawAddress, i32), |
| ResponseConfirmation(i32, i32), |
| IndicationSent(i32, i32), |
| Congestion(i32, bool), |
| MtuChanged(i32, i32), |
| PhyUpdated(i32, u8, u8, u8), |
| ConnUpdated(i32, u16, u16, u16, u8), |
| } |
| |
| pub struct GattClientCallbacksDispatcher { |
| pub dispatch: Box<dyn Fn(GattClientCallbacks) + Send>, |
| } |
| |
| pub struct GattServerCallbacksDispatcher { |
| pub dispatch: Box<dyn Fn(GattServerCallbacks) + Send>, |
| } |
| |
| type GattClientCb = Arc<Mutex<GattClientCallbacksDispatcher>>; |
| type GattServerCb = Arc<Mutex<GattServerCallbacksDispatcher>>; |
| |
| cb_variant!( |
| GattClientCb, |
| gc_register_client_cb -> GattClientCallbacks::RegisterClient, |
| i32, i32, *const Uuid, { |
| let _2 = unsafe { *_2.clone() }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_open_cb -> GattClientCallbacks::Connect, |
| i32, i32, i32, *const FfiAddress, { |
| let _3 = unsafe { deref_ffi_address!(_3) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_close_cb -> GattClientCallbacks::Disconnect, |
| i32, i32, i32, *const FfiAddress, { |
| let _3 = unsafe { deref_ffi_address!(_3) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_search_complete_cb -> GattClientCallbacks::SearchComplete, |
| i32, i32, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_register_for_notification_cb -> GattClientCallbacks::RegisterForNotification, |
| i32, i32, i32, 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, *mut BtGattReadParams, { |
| let _2 = unsafe { *_2.clone() }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_write_characteristic_cb -> GattClientCallbacks::WriteCharacteristic, |
| i32, i32, u16, u16, *const u8, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_read_descriptor_cb -> GattClientCallbacks::ReadDescriptor, |
| i32, i32, *const BtGattReadParams, { |
| let _2 = unsafe { *_2.clone() }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_write_descriptor_cb -> GattClientCallbacks::WriteDescriptor, |
| i32, i32, u16, u16, *const u8, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_execute_write_cb -> GattClientCallbacks::ExecuteWrite, |
| i32, i32, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_read_remote_rssi_cb -> GattClientCallbacks::ReadRemoteRssi, |
| i32, *const FfiAddress, i32, i32, { |
| let _1 = unsafe { deref_ffi_address!(_1) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_configure_mtu_cb -> GattClientCallbacks::ConfigureMtu, |
| i32, i32, 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, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_conn_updated_cb -> GattClientCallbacks::ConnUpdated, |
| i32, u16, u16, u16, u8, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| gc_service_changed_cb -> GattClientCallbacks::ServiceChanged, |
| i32, {} |
| ); |
| |
| cb_variant!( |
| GattClientCb, |
| read_phy_callback -> GattClientCallbacks::ReadPhy, |
| i32, ffi::RustRawAddress -> RawAddress, u8, u8, u8, { |
| let _1 = RawAddress { val: _1.address }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_register_server_cb -> GattServerCallbacks::RegisterServer, |
| i32, i32, *const Uuid, { |
| let _2 = unsafe { *_2.clone() }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_connection_cb -> GattServerCallbacks::Connection, |
| i32, i32, i32, *const FfiAddress, { |
| let _3 = unsafe { deref_ffi_address!(_3) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_service_added_cb -> GattServerCallbacks::ServiceAdded, |
| i32, i32, *const BtGattDbElement, usize, { |
| let _2 = ptr_to_vec(_2, _3); |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_service_stopped_cb -> GattServerCallbacks::ServiceStopped, |
| i32, i32, i32, {} |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_service_deleted_cb -> GattServerCallbacks::ServiceDeleted, |
| i32, i32, i32, {} |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_request_read_characteristic_cb -> GattServerCallbacks::RequestReadCharacteristic, |
| i32, i32, *const FfiAddress, i32, i32, bool, { |
| let _2 = unsafe { deref_ffi_address!(_2) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_request_read_descriptor_cb -> GattServerCallbacks::RequestReadDescriptor, |
| i32, i32, *const FfiAddress, i32, i32, bool, { |
| let _2 = unsafe { deref_ffi_address!(_2) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_request_write_characteristic_cb -> GattServerCallbacks::RequestWriteCharacteristic, |
| i32, i32, *const FfiAddress, i32, i32, bool, bool, *const u8, usize, { |
| let _2 = unsafe { deref_ffi_address!(_2) }; |
| let _7 = ptr_to_vec(_7, _8); |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_request_write_descriptor_cb -> GattServerCallbacks::RequestWriteDescriptor, |
| i32, i32, *const FfiAddress, i32, i32, bool, bool, *const u8, usize, { |
| let _2 = unsafe { deref_ffi_address!(_2) }; |
| let _7 = ptr_to_vec(_7, _8); |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_request_exec_write_cb -> GattServerCallbacks::RequestExecWrite, |
| i32, i32, *const FfiAddress, i32, { |
| let _2 = unsafe { deref_ffi_address!(_2) }; |
| } |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_response_confirmation_cb -> GattServerCallbacks::ResponseConfirmation, |
| i32, i32, {} |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_indication_sent_cb -> GattServerCallbacks::IndicationSent, |
| i32, i32, {} |
| ); |
| |
| 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, {} |
| ); |
| |
| cb_variant!( |
| GattServerCb, |
| gs_conn_updated_cb -> GattServerCallbacks::ConnUpdated, |
| i32, u16, u16, u16, u8, {} |
| ); |
| |
| 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 {} |
| |
| pub struct GattClient { |
| internal: RawGattClientWrapper, |
| internal_cxx: cxx::UniquePtr<ffi::GattClientIntf>, |
| } |
| |
| 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, |
| is_direct: bool, |
| transport: i32, |
| opportunistic: bool, |
| initiating_phys: i32, |
| ) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!( |
| self, |
| connect, |
| client_if, |
| ffi_addr, |
| is_direct, |
| transport, |
| opportunistic, |
| initiating_phys |
| )) |
| } |
| |
| pub fn disconnect(&self, client_if: i32, addr: &RawAddress, conn_id: i32) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, disconnect, client_if, ffi_addr, conn_id)) |
| } |
| |
| pub fn refresh(&self, client_if: i32, addr: &RawAddress) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, refresh, client_if, ffi_addr)) |
| } |
| |
| pub fn search_service(&self, conn_id: i32, filter_uuid: Option<Uuid>) -> BtStatus { |
| let filter_uuid_ptr = match filter_uuid { |
| None => std::ptr::null(), |
| Some(uuid) => &uuid, |
| }; |
| |
| BtStatus::from(ccall!(self, search_service, conn_id, filter_uuid_ptr)) |
| } |
| |
| 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 { |
| BtStatus::from(ccall!( |
| self, |
| write_characteristic, |
| conn_id, |
| handle, |
| write_type, |
| auth_req, |
| value.as_ptr(), |
| 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 { |
| BtStatus::from(ccall!( |
| self, |
| write_descriptor, |
| conn_id, |
| handle, |
| auth_req, |
| value.as_ptr(), |
| 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 { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, register_for_notification, client_if, ffi_addr, handle)) |
| } |
| |
| pub fn deregister_for_notification( |
| &self, |
| client_if: i32, |
| addr: &RawAddress, |
| handle: u16, |
| ) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, deregister_for_notification, client_if, ffi_addr, handle)) |
| } |
| |
| pub fn read_remote_rssi(&self, client_if: i32, addr: &RawAddress) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, read_remote_rssi, client_if, ffi_addr)) |
| } |
| |
| pub fn get_device_type(&self, addr: &RawAddress) -> i32 { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| ccall!(self, get_device_type, ffi_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 { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!( |
| self, |
| conn_parameter_update, |
| ffi_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 { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, set_preferred_phy, ffi_addr, tx_phy, rx_phy, phy_options)) |
| } |
| |
| pub fn read_phy(&mut self, client_if: i32, addr: &RawAddress) -> BtStatus { |
| BtStatus::from_i32( |
| self.internal_cxx |
| .pin_mut() |
| .read_phy(client_if, ffi::RustRawAddress { address: addr.val }), |
| ) |
| .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, |
| } |
| |
| 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, |
| is_direct: bool, |
| transport: i32, |
| ) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, connect, server_if, ffi_addr, is_direct, transport)) |
| } |
| |
| pub fn disconnect(&self, server_if: i32, addr: &RawAddress, conn_id: i32) -> BtStatus { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, disconnect, server_if, ffi_addr, conn_id)) |
| } |
| |
| pub fn add_service(&self, server_if: i32, service: &[BtGattDbElement]) -> BtStatus { |
| BtStatus::from(ccall!(self, add_service, server_if, service.as_ptr(), 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 { |
| BtStatus::from(ccall!( |
| self, |
| send_indication, |
| server_if, |
| attribute_handle, |
| conn_id, |
| confirm, |
| value.as_ptr(), |
| 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 { |
| let ffi_addr = cast_to_ffi_address!(addr as *const RawAddress); |
| BtStatus::from(ccall!(self, set_preferred_phy, ffi_addr, tx_phy, rx_phy, phy_options)) |
| } |
| |
| // TODO(b/193916778): Figure out how to shim read_phy which accepts base::Callback |
| } |
| |
| // TODO(b/193916778): Underlying FFI is C++, implement using cxx. |
| pub struct BleScanner { |
| _internal: RawBleScannerWrapper, |
| } |
| |
| // TODO(b/193916778): Underlying FFI is C++, implement using cxx. |
| pub struct BleAdvertiser { |
| _internal: RawBleAdvertiserWrapper, |
| } |
| |
| 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<Box<bindings::btgatt_callbacks_t>>, |
| gatt_client_callbacks: Option<Box<bindings::btgatt_client_callbacks_t>>, |
| gatt_server_callbacks: Option<Box<bindings::btgatt_server_callbacks_t>>, |
| gatt_scanner_callbacks: Option<Box<bindings::btgatt_scanner_callbacks_t>>, |
| } |
| |
| impl Gatt { |
| pub fn new(intf: &BluetoothInterface) -> Option<Gatt> { |
| 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) }; |
| |
| 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 |
| }, |
| }, |
| }, |
| scanner: BleScanner { |
| _internal: RawBleScannerWrapper { |
| _raw: unsafe { |
| (*(r as *const btgatt_interface_t)).scanner as *const BleScannerInterface |
| }, |
| }, |
| }, |
| advertiser: BleAdvertiser { |
| _internal: RawBleAdvertiserWrapper { |
| _raw: unsafe { |
| (*(r as *const btgatt_interface_t)).scanner as *const BleAdvertiserInterface |
| }, |
| }, |
| }, |
| 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, |
| ) -> bool { |
| // Register dispatcher |
| if get_dispatchers() |
| .lock() |
| .unwrap() |
| .set::<GattClientCb>(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::<GattServerCb>(Arc::new(Mutex::new(gatt_server_callbacks_dispatcher))) |
| { |
| panic!("Tried to set dispatcher for GattServerCallbacks but it already existed"); |
| } |
| |
| let mut 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, |
| }); |
| |
| let mut 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), |
| }); |
| |
| let mut 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 mut callbacks = Box::new(btgatt_callbacks_t { |
| size: 4 * 8, |
| client: &mut *gatt_client_callbacks, |
| server: &mut *gatt_server_callbacks, |
| scanner: &mut *gatt_scanner_callbacks, |
| }); |
| |
| let rawcb = &mut *callbacks; |
| |
| let init = ccall!(self, init, rawcb); |
| 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); |
| |
| return self.is_init; |
| } |
| } |