Loading system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs +23 −1 Original line number Diff line number Diff line use btstack::bluetooth_gatt::{ IBluetoothGatt, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType, IBluetoothGatt, IBluetoothGattCallback, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType, }; use btstack::RPCProxy; Loading @@ -19,6 +20,15 @@ use std::sync::Arc; use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust}; #[allow(dead_code)] struct BluetoothGattCallbackDBus {} #[dbus_proxy_obj(BluetoothGattCallback, "org.chromium.bluetooth.BluetoothGattCallback")] impl IBluetoothGattCallback for BluetoothGattCallbackDBus { #[dbus_method("OnClientRegistered")] fn on_client_registered(&self, _status: i32, _scanner_id: i32) {} } #[allow(dead_code)] struct ScannerCallbackDBus {} Loading Loading @@ -63,4 +73,16 @@ impl IBluetoothGatt for IBluetoothGattDBus { #[dbus_method("StopScan")] fn stop_scan(&self, scanner_id: i32) {} #[dbus_method("RegisterClient")] fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ) { } #[dbus_method("UnregisterClient")] fn unregister_client(&self, client_if: i32) {} } system/gd/rust/linux/service/src/main.rs +10 −3 Original line number Diff line number Diff line Loading @@ -63,10 +63,16 @@ fn main() -> Result<(), Box<dyn Error>> { let adapter_index = get_adapter_index(&args); intf.lock().unwrap().initialize(get_bt_dispatcher(tx), args); // Hold locks and initialize all interfaces. { intf.lock().unwrap().initialize(get_bt_dispatcher(tx.clone()), args); bluetooth.lock().unwrap().init_profiles(); bluetooth.lock().unwrap().enable(); let mut bluetooth = bluetooth.lock().unwrap(); bluetooth.init_profiles(); bluetooth.enable(); bluetooth_gatt.lock().unwrap().init_profiles(tx.clone()); } topstack::get_runtime().block_on(async { // Connect to D-Bus system bus. Loading Loading @@ -95,6 +101,7 @@ fn main() -> Result<(), Box<dyn Error>> { topstack::get_runtime().spawn(Stack::dispatch( rx, bluetooth.clone(), bluetooth_gatt.clone(), bluetooth_media.clone(), )); Loading system/gd/rust/linux/stack/src/bluetooth_gatt.rs +138 −3 Original line number Diff line number Diff line //! Anything related to the GATT API (IBluetoothGatt). use bt_topshim::btif::BluetoothInterface; use btif_macros::{btif_callback, btif_callbacks_dispatcher}; use bt_topshim::bindings::root::bluetooth::Uuid; use bt_topshim::btif::{BluetoothInterface, RawAddress}; use bt_topshim::profiles::gatt::{ Gatt, GattClientCallbacks, GattClientCallbacksDispatcher, GattServerCallbacksDispatcher, }; use bt_topshim::topstack; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; use crate::{Message, RPCProxy}; /// Defines the GATT API. pub trait IBluetoothGatt { fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>); Loading @@ -12,6 +24,23 @@ pub trait IBluetoothGatt { fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>); fn stop_scan(&self, scanner_id: i32); /// Registers a GATT Client. fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ); /// Unregisters a GATT Client. fn unregister_client(&self, client_if: i32); } /// Callback for GATT Client API. pub trait IBluetoothGattCallback: RPCProxy { /// When the `register_client` request is done. fn on_client_registered(&self, status: i32, client_if: i32); } /// Interface for scanner callbacks to clients, passed to `IBluetoothGatt::register_scanner`. Loading Loading @@ -55,16 +84,61 @@ pub struct ScanSettings { #[derive(Debug, Default)] pub struct ScanFilter {} type Uuid128Bit = [u8; 16]; /// Implementation of the GATT API (IBluetoothGatt). pub struct BluetoothGatt { _intf: Arc<Mutex<BluetoothInterface>>, intf: Arc<Mutex<BluetoothInterface>>, gatt: Option<Gatt>, gatt_client_map: HashMap<Uuid128Bit, Box<dyn IBluetoothGattCallback + Send>>, } impl BluetoothGatt { /// Constructs a new IBluetoothGatt implementation. pub fn new(intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothGatt { BluetoothGatt { _intf: intf } BluetoothGatt { intf: intf, gatt: None, gatt_client_map: HashMap::new() } } pub fn init_profiles(&mut self, tx: Sender<Message>) { self.gatt = Gatt::new(&self.intf.lock().unwrap()); self.gatt.as_mut().unwrap().initialize( GattClientCallbacksDispatcher { dispatch: Box::new(move |cb| { let tx_clone = tx.clone(); topstack::get_runtime().spawn(async move { let _ = tx_clone.send(Message::GattClient(cb)).await; }); }), }, GattServerCallbacksDispatcher { dispatch: Box::new(move |cb| { // TODO(b/193685149): Implement the callbacks println!("received Gatt server callback: {:?}", cb); }), }, ); } } // Temporary util that covers only basic string conversion. // TODO(b/193685325): Implement more UUID utils by using Uuid from gd/hci/uuid.h with cxx. fn parse_uuid_string(uuid: String) -> Option<Uuid> { if uuid.len() != 32 { return None; } let mut raw = [0; 16]; for i in 0..16 { let byte = u8::from_str_radix(&uuid[i * 2..i * 2 + 2], 16); if byte.is_err() { return None; } raw[i] = byte.unwrap(); } Some(Uuid { uu: raw }) } impl IBluetoothGatt for BluetoothGatt { Loading @@ -83,4 +157,65 @@ impl IBluetoothGatt for BluetoothGatt { fn stop_scan(&self, _scanner_id: i32) { // TODO: implement } fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ) { let uuid = parse_uuid_string(app_uuid).unwrap(); self.gatt_client_map.insert(uuid.uu, callback); self.gatt.as_ref().unwrap().client.register_client(&uuid, eatt_support); } fn unregister_client(&self, _client_if: i32) { // TODO(b/193685325): implement } } #[btif_callbacks_dispatcher(BluetoothGatt, dispatch_gatt_client_callbacks, GattClientCallbacks)] pub(crate) trait BtifGattClientCallbacks { #[btif_callback(RegisterClient)] fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid); #[btif_callback(Connect)] fn connect_cb(&mut self, conn_id: i32, status: i32, client_if: i32, addr: RawAddress); // TODO(b/193685325): Define all callbacks. } impl BtifGattClientCallbacks for BluetoothGatt { fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid) { let callback = self.gatt_client_map.get(&app_uuid.uu); if callback.is_none() { println!("Warning: Callback not registered for UUID {:?}", app_uuid.uu); return; } callback.unwrap().on_client_registered(status, client_if); } fn connect_cb(&mut self, _conn_id: i32, _status: i32, _client_if: i32, _addr: RawAddress) { // TODO(b/193685325): handle; } } #[cfg(test)] mod tests { use super::*; #[test] fn test_uuid_from_string() { let uuid = parse_uuid_string(String::from("abcdef")); assert!(uuid.is_none()); let uuid = parse_uuid_string(String::from("0123456789abcdef0123456789abcdef")); assert!(uuid.is_some()); let expected: [u8; 16] = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, ]; assert_eq!(Uuid { uu: expected }, uuid.unwrap()); } } system/gd/rust/linux/stack/src/lib.rs +16 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ pub mod bluetooth_media; use bt_topshim::btif::BaseCallbacks; use bt_topshim::profiles::a2dp::A2dpCallbacks; use bt_topshim::profiles::gatt::GattClientCallbacks; use bt_topshim::profiles::gatt::GattServerCallbacks; use std::sync::{Arc, Mutex}; Loading @@ -19,6 +21,7 @@ use tokio::sync::mpsc::channel; use tokio::sync::mpsc::{Receiver, Sender}; use crate::bluetooth::Bluetooth; use crate::bluetooth_gatt::BluetoothGatt; use crate::bluetooth_media::BluetoothMedia; /// Represents a Bluetooth address. Loading @@ -28,6 +31,8 @@ use crate::bluetooth_media::BluetoothMedia; pub enum Message { A2dp(A2dpCallbacks), Base(BaseCallbacks), GattClient(GattClientCallbacks), GattServer(GattServerCallbacks), BluetoothCallbackDisconnected(u32), } Loading @@ -44,6 +49,7 @@ impl Stack { pub async fn dispatch( mut rx: Receiver<Message>, bluetooth: Arc<Mutex<Box<Bluetooth>>>, bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>, ) { loop { Loading @@ -58,10 +64,20 @@ impl Stack { Message::A2dp(a) => { bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a); } Message::Base(b) => { bluetooth.lock().unwrap().dispatch_base_callbacks(b); } Message::GattClient(m) => { bluetooth_gatt.lock().unwrap().dispatch_gatt_client_callbacks(m); } Message::GattServer(m) => { // TODO(b/193685149): dispatch GATT server callbacks. println!("Unhandled Message::GattServer: {:?}", m); } Message::BluetoothCallbackDisconnected(id) => { bluetooth.lock().unwrap().callback_disconnected(id); } Loading Loading
system/gd/rust/linux/service/src/iface_bluetooth_gatt.rs +23 −1 Original line number Diff line number Diff line use btstack::bluetooth_gatt::{ IBluetoothGatt, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType, IBluetoothGatt, IBluetoothGattCallback, IScannerCallback, RSSISettings, ScanFilter, ScanSettings, ScanType, }; use btstack::RPCProxy; Loading @@ -19,6 +20,15 @@ use std::sync::Arc; use crate::dbus_arg::{DBusArg, DBusArgError, RefArgToRust}; #[allow(dead_code)] struct BluetoothGattCallbackDBus {} #[dbus_proxy_obj(BluetoothGattCallback, "org.chromium.bluetooth.BluetoothGattCallback")] impl IBluetoothGattCallback for BluetoothGattCallbackDBus { #[dbus_method("OnClientRegistered")] fn on_client_registered(&self, _status: i32, _scanner_id: i32) {} } #[allow(dead_code)] struct ScannerCallbackDBus {} Loading Loading @@ -63,4 +73,16 @@ impl IBluetoothGatt for IBluetoothGattDBus { #[dbus_method("StopScan")] fn stop_scan(&self, scanner_id: i32) {} #[dbus_method("RegisterClient")] fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ) { } #[dbus_method("UnregisterClient")] fn unregister_client(&self, client_if: i32) {} }
system/gd/rust/linux/service/src/main.rs +10 −3 Original line number Diff line number Diff line Loading @@ -63,10 +63,16 @@ fn main() -> Result<(), Box<dyn Error>> { let adapter_index = get_adapter_index(&args); intf.lock().unwrap().initialize(get_bt_dispatcher(tx), args); // Hold locks and initialize all interfaces. { intf.lock().unwrap().initialize(get_bt_dispatcher(tx.clone()), args); bluetooth.lock().unwrap().init_profiles(); bluetooth.lock().unwrap().enable(); let mut bluetooth = bluetooth.lock().unwrap(); bluetooth.init_profiles(); bluetooth.enable(); bluetooth_gatt.lock().unwrap().init_profiles(tx.clone()); } topstack::get_runtime().block_on(async { // Connect to D-Bus system bus. Loading Loading @@ -95,6 +101,7 @@ fn main() -> Result<(), Box<dyn Error>> { topstack::get_runtime().spawn(Stack::dispatch( rx, bluetooth.clone(), bluetooth_gatt.clone(), bluetooth_media.clone(), )); Loading
system/gd/rust/linux/stack/src/bluetooth_gatt.rs +138 −3 Original line number Diff line number Diff line //! Anything related to the GATT API (IBluetoothGatt). use bt_topshim::btif::BluetoothInterface; use btif_macros::{btif_callback, btif_callbacks_dispatcher}; use bt_topshim::bindings::root::bluetooth::Uuid; use bt_topshim::btif::{BluetoothInterface, RawAddress}; use bt_topshim::profiles::gatt::{ Gatt, GattClientCallbacks, GattClientCallbacksDispatcher, GattServerCallbacksDispatcher, }; use bt_topshim::topstack; use std::collections::HashMap; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc::Sender; use crate::{Message, RPCProxy}; /// Defines the GATT API. pub trait IBluetoothGatt { fn register_scanner(&self, callback: Box<dyn IScannerCallback + Send>); Loading @@ -12,6 +24,23 @@ pub trait IBluetoothGatt { fn start_scan(&self, scanner_id: i32, settings: ScanSettings, filters: Vec<ScanFilter>); fn stop_scan(&self, scanner_id: i32); /// Registers a GATT Client. fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ); /// Unregisters a GATT Client. fn unregister_client(&self, client_if: i32); } /// Callback for GATT Client API. pub trait IBluetoothGattCallback: RPCProxy { /// When the `register_client` request is done. fn on_client_registered(&self, status: i32, client_if: i32); } /// Interface for scanner callbacks to clients, passed to `IBluetoothGatt::register_scanner`. Loading Loading @@ -55,16 +84,61 @@ pub struct ScanSettings { #[derive(Debug, Default)] pub struct ScanFilter {} type Uuid128Bit = [u8; 16]; /// Implementation of the GATT API (IBluetoothGatt). pub struct BluetoothGatt { _intf: Arc<Mutex<BluetoothInterface>>, intf: Arc<Mutex<BluetoothInterface>>, gatt: Option<Gatt>, gatt_client_map: HashMap<Uuid128Bit, Box<dyn IBluetoothGattCallback + Send>>, } impl BluetoothGatt { /// Constructs a new IBluetoothGatt implementation. pub fn new(intf: Arc<Mutex<BluetoothInterface>>) -> BluetoothGatt { BluetoothGatt { _intf: intf } BluetoothGatt { intf: intf, gatt: None, gatt_client_map: HashMap::new() } } pub fn init_profiles(&mut self, tx: Sender<Message>) { self.gatt = Gatt::new(&self.intf.lock().unwrap()); self.gatt.as_mut().unwrap().initialize( GattClientCallbacksDispatcher { dispatch: Box::new(move |cb| { let tx_clone = tx.clone(); topstack::get_runtime().spawn(async move { let _ = tx_clone.send(Message::GattClient(cb)).await; }); }), }, GattServerCallbacksDispatcher { dispatch: Box::new(move |cb| { // TODO(b/193685149): Implement the callbacks println!("received Gatt server callback: {:?}", cb); }), }, ); } } // Temporary util that covers only basic string conversion. // TODO(b/193685325): Implement more UUID utils by using Uuid from gd/hci/uuid.h with cxx. fn parse_uuid_string(uuid: String) -> Option<Uuid> { if uuid.len() != 32 { return None; } let mut raw = [0; 16]; for i in 0..16 { let byte = u8::from_str_radix(&uuid[i * 2..i * 2 + 2], 16); if byte.is_err() { return None; } raw[i] = byte.unwrap(); } Some(Uuid { uu: raw }) } impl IBluetoothGatt for BluetoothGatt { Loading @@ -83,4 +157,65 @@ impl IBluetoothGatt for BluetoothGatt { fn stop_scan(&self, _scanner_id: i32) { // TODO: implement } fn register_client( &mut self, app_uuid: String, callback: Box<dyn IBluetoothGattCallback + Send>, eatt_support: bool, ) { let uuid = parse_uuid_string(app_uuid).unwrap(); self.gatt_client_map.insert(uuid.uu, callback); self.gatt.as_ref().unwrap().client.register_client(&uuid, eatt_support); } fn unregister_client(&self, _client_if: i32) { // TODO(b/193685325): implement } } #[btif_callbacks_dispatcher(BluetoothGatt, dispatch_gatt_client_callbacks, GattClientCallbacks)] pub(crate) trait BtifGattClientCallbacks { #[btif_callback(RegisterClient)] fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid); #[btif_callback(Connect)] fn connect_cb(&mut self, conn_id: i32, status: i32, client_if: i32, addr: RawAddress); // TODO(b/193685325): Define all callbacks. } impl BtifGattClientCallbacks for BluetoothGatt { fn register_client_cb(&mut self, status: i32, client_if: i32, app_uuid: Uuid) { let callback = self.gatt_client_map.get(&app_uuid.uu); if callback.is_none() { println!("Warning: Callback not registered for UUID {:?}", app_uuid.uu); return; } callback.unwrap().on_client_registered(status, client_if); } fn connect_cb(&mut self, _conn_id: i32, _status: i32, _client_if: i32, _addr: RawAddress) { // TODO(b/193685325): handle; } } #[cfg(test)] mod tests { use super::*; #[test] fn test_uuid_from_string() { let uuid = parse_uuid_string(String::from("abcdef")); assert!(uuid.is_none()); let uuid = parse_uuid_string(String::from("0123456789abcdef0123456789abcdef")); assert!(uuid.is_some()); let expected: [u8; 16] = [ 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, ]; assert_eq!(Uuid { uu: expected }, uuid.unwrap()); } }
system/gd/rust/linux/stack/src/lib.rs +16 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,8 @@ pub mod bluetooth_media; use bt_topshim::btif::BaseCallbacks; use bt_topshim::profiles::a2dp::A2dpCallbacks; use bt_topshim::profiles::gatt::GattClientCallbacks; use bt_topshim::profiles::gatt::GattServerCallbacks; use std::sync::{Arc, Mutex}; Loading @@ -19,6 +21,7 @@ use tokio::sync::mpsc::channel; use tokio::sync::mpsc::{Receiver, Sender}; use crate::bluetooth::Bluetooth; use crate::bluetooth_gatt::BluetoothGatt; use crate::bluetooth_media::BluetoothMedia; /// Represents a Bluetooth address. Loading @@ -28,6 +31,8 @@ use crate::bluetooth_media::BluetoothMedia; pub enum Message { A2dp(A2dpCallbacks), Base(BaseCallbacks), GattClient(GattClientCallbacks), GattServer(GattServerCallbacks), BluetoothCallbackDisconnected(u32), } Loading @@ -44,6 +49,7 @@ impl Stack { pub async fn dispatch( mut rx: Receiver<Message>, bluetooth: Arc<Mutex<Box<Bluetooth>>>, bluetooth_gatt: Arc<Mutex<Box<BluetoothGatt>>>, bluetooth_media: Arc<Mutex<Box<BluetoothMedia>>>, ) { loop { Loading @@ -58,10 +64,20 @@ impl Stack { Message::A2dp(a) => { bluetooth_media.lock().unwrap().dispatch_a2dp_callbacks(a); } Message::Base(b) => { bluetooth.lock().unwrap().dispatch_base_callbacks(b); } Message::GattClient(m) => { bluetooth_gatt.lock().unwrap().dispatch_gatt_client_callbacks(m); } Message::GattServer(m) => { // TODO(b/193685149): dispatch GATT server callbacks. println!("Unhandled Message::GattServer: {:?}", m); } Message::BluetoothCallbackDisconnected(id) => { bluetooth.lock().unwrap().callback_disconnected(id); } Loading