From 42efb72cb29cf5e026cc3c47fe74ccca39ea446f Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Tue, 12 Nov 2024 09:11:28 -0700 Subject: [PATCH 1/6] Implemented Windows MTU --- src/api/mod.rs | 3 +++ src/winrtble/ble/device.rs | 31 ++++++++++++++++++++++++++++++- src/winrtble/peripheral.rs | 34 ++++++++++++++++++++++++++++------ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index bb3acf68..03e3a99b 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -230,6 +230,9 @@ pub trait Peripheral: Send + Sync + Clone + Debug { /// Returns the MAC address of the peripheral. fn address(&self) -> BDAddr; + /// Returns the currently negotiated mtu size + fn mtu(&self) -> u16; + /// Returns the set of properties associated with the peripheral. These may be updated over time /// as additional advertising reports are received. async fn properties(&self) -> Result>; diff --git a/src/winrtble/ble/device.rs b/src/winrtble/ble/device.rs index 9fd2707f..f5d95b66 100644 --- a/src/winrtble/ble/device.rs +++ b/src/winrtble/ble/device.rs @@ -18,17 +18,20 @@ use windows::{ BluetoothCacheMode, BluetoothConnectionStatus, BluetoothLEDevice, GenericAttributeProfile::{ GattCharacteristic, GattCommunicationStatus, GattDescriptor, GattDeviceService, - GattDeviceServicesResult, + GattDeviceServicesResult, GattSession, }, }, Foundation::{EventRegistrationToken, TypedEventHandler}, }; pub type ConnectedEventHandler = Box; +pub type MaxPduSizeChangedEventHandler = Box; pub struct BLEDevice { device: BluetoothLEDevice, + gatt_session: GattSession, connection_token: EventRegistrationToken, + pdu_change_token: EventRegistrationToken, services: Vec, } @@ -36,10 +39,16 @@ impl BLEDevice { pub async fn new( address: BDAddr, connection_status_changed: ConnectedEventHandler, + max_pdu_size_changed: MaxPduSizeChangedEventHandler, ) -> Result { let async_op = BluetoothLEDevice::FromBluetoothAddressAsync(address.into()) .map_err(|_| Error::DeviceNotFound)?; let device = async_op.await.map_err(|_| Error::DeviceNotFound)?; + + let async_op = GattSession::FromDeviceIdAsync(&device.BluetoothDeviceId()?) + .map_err(|_| Error::DeviceNotFound)?; + let gatt_session = async_op.await.map_err(|_| Error::DeviceNotFound)?; + let connection_status_handler = TypedEventHandler::new(move |sender: &Option, _| { if let Some(sender) = sender { @@ -57,9 +66,22 @@ impl BLEDevice { .ConnectionStatusChanged(&connection_status_handler) .map_err(|_| Error::Other("Could not add connection status handler".into()))?; + let max_pdu_size_changed_handler = + TypedEventHandler::new(move |sender: &Option, _| { + if let Some(sender) = sender { + max_pdu_size_changed(sender.MaxPduSize().unwrap()); + } + Ok(()) + }); + let pdu_change_token = gatt_session + .MaxPduSizeChanged(&max_pdu_size_changed_handler) + .map_err(|_| Error::Other("Could not add max pdu size changed handler".into()))?; + Ok(BLEDevice { device, + gatt_session, connection_token, + pdu_change_token, services: vec![], }) } @@ -167,6 +189,13 @@ impl BLEDevice { impl Drop for BLEDevice { fn drop(&mut self) { + let result = self + .gatt_session + .RemoveMaxPduSizeChanged(self.pdu_change_token); + if let Err(err) = result { + debug!("Drop: remove_max_pdu_size_changed {:?}", err); + } + let result = self .device .RemoveConnectionStatusChanged(self.connection_token); diff --git a/src/winrtble/peripheral.rs b/src/winrtble/peripheral.rs index fda061f9..8160b2e1 100644 --- a/src/winrtble/peripheral.rs +++ b/src/winrtble/peripheral.rs @@ -37,7 +37,7 @@ use std::{ convert::TryInto, fmt::{self, Debug, Display, Formatter}, pin::Pin, - sync::atomic::{AtomicBool, Ordering}, + sync::atomic::{AtomicBool, AtomicU16, Ordering}, sync::{Arc, RwLock}, }; use tokio::sync::broadcast; @@ -70,6 +70,7 @@ struct Shared { device: tokio::sync::Mutex>, adapter: Weak>, address: BDAddr, + mtu: AtomicU16, connected: AtomicBool, ble_services: DashMap, notifications_channel: broadcast::Sender, @@ -93,6 +94,7 @@ impl Peripheral { adapter, device: tokio::sync::Mutex::new(None), address, + mtu: AtomicU16::new(23), connected: AtomicBool::new(false), ble_services: DashMap::new(), notifications_channel: broadcast_sender, @@ -341,6 +343,11 @@ impl ApiPeripheral for Peripheral { self.shared.address } + /// Returns the currently negotiated mtu size + fn mtu(&self) -> u16 { + self.shared.mtu.load(Ordering::Relaxed) + } + /// Returns the set of properties associated with the peripheral. These may be updated over time /// as additional advertising reports are received. async fn properties(&self) -> Result> { @@ -364,12 +371,12 @@ impl ApiPeripheral for Peripheral { /// Ok there has been successful connection. Note that peripherals allow only one connection at /// a time. Operations that attempt to communicate with a device will fail until it is connected. async fn connect(&self) -> Result<()> { - let shared_clone = Arc::downgrade(&self.shared); let adapter_clone = self.shared.adapter.clone(); let address = self.shared.address; - let device = BLEDevice::new( - self.shared.address, - Box::new(move |is_connected| { + + let connection_status_changed = Box::new({ + let shared_clone = Arc::downgrade(&self.shared); + move |is_connected| { if let Some(shared) = shared_clone.upgrade() { shared.connected.store(is_connected, Ordering::Relaxed); } @@ -379,7 +386,22 @@ impl ApiPeripheral for Peripheral { adapter.emit(CentralEvent::DeviceDisconnected(address.into())); } } - }), + } + }); + + let max_pdu_size_changed = Box::new({ + let shared_clone = Arc::downgrade(&self.shared); + move |mtu| { + if let Some(shared) = shared_clone.upgrade() { + shared.mtu.store(mtu, Ordering::Relaxed); + } + } + }); + + let device = BLEDevice::new( + self.shared.address, + connection_status_changed, + max_pdu_size_changed, ) .await?; From 533ae404cbf17c15b24e0cde8f34dce75a0a05a8 Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Tue, 12 Nov 2024 10:27:59 -0700 Subject: [PATCH 2/6] Added initial MTU assignment prior to event handler registration --- src/winrtble/ble/device.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/winrtble/ble/device.rs b/src/winrtble/ble/device.rs index f5d95b66..3cb111f9 100644 --- a/src/winrtble/ble/device.rs +++ b/src/winrtble/ble/device.rs @@ -66,6 +66,7 @@ impl BLEDevice { .ConnectionStatusChanged(&connection_status_handler) .map_err(|_| Error::Other("Could not add connection status handler".into()))?; + max_pdu_size_changed(gatt_session.MaxPduSize().unwrap()); let max_pdu_size_changed_handler = TypedEventHandler::new(move |sender: &Option, _| { if let Some(sender) = sender { From 750dd28dbf3e945ecbc0bce006a38fc8020d529b Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Tue, 12 Nov 2024 10:48:56 -0700 Subject: [PATCH 3/6] Added a constant for default MTU size --- src/winrtble/peripheral.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/winrtble/peripheral.rs b/src/winrtble/peripheral.rs index 8160b2e1..43902d1e 100644 --- a/src/winrtble/peripheral.rs +++ b/src/winrtble/peripheral.rs @@ -46,6 +46,9 @@ use uuid::Uuid; use std::sync::Weak; use windows::Devices::Bluetooth::{Advertisement::*, BluetoothAddressType}; +/// The default MTU size for a peripheral. +const DEFAULT_MTU_SIZE: u16 = 23; + #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -94,7 +97,7 @@ impl Peripheral { adapter, device: tokio::sync::Mutex::new(None), address, - mtu: AtomicU16::new(23), + mtu: AtomicU16::new(DEFAULT_MTU_SIZE), connected: AtomicBool::new(false), ble_services: DashMap::new(), notifications_channel: broadcast_sender, From 88c232de69e1eaa6a7108404ae20b9024729babc Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Fri, 20 Dec 2024 13:51:17 -0700 Subject: [PATCH 4/6] Moved constant to somewhere more accessible --- src/api/mod.rs | 3 +++ src/winrtble/peripheral.rs | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/mod.rs b/src/api/mod.rs index 03e3a99b..36d50da7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -43,6 +43,9 @@ pub use self::bdaddr::{BDAddr, ParseBDAddrError}; use crate::platform::PeripheralId; +/// The default MTU size for a peripheral. +pub const DEFAULT_MTU_SIZE: u16 = 23; + #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), diff --git a/src/winrtble/peripheral.rs b/src/winrtble/peripheral.rs index 43902d1e..8ff0d1f4 100644 --- a/src/winrtble/peripheral.rs +++ b/src/winrtble/peripheral.rs @@ -46,9 +46,6 @@ use uuid::Uuid; use std::sync::Weak; use windows::Devices::Bluetooth::{Advertisement::*, BluetoothAddressType}; -/// The default MTU size for a peripheral. -const DEFAULT_MTU_SIZE: u16 = 23; - #[cfg_attr( feature = "serde", derive(Serialize, Deserialize), @@ -97,7 +94,7 @@ impl Peripheral { adapter, device: tokio::sync::Mutex::new(None), address, - mtu: AtomicU16::new(DEFAULT_MTU_SIZE), + mtu: AtomicU16::new(api::DEFAULT_MTU_SIZE), connected: AtomicBool::new(false), ble_services: DashMap::new(), notifications_channel: broadcast_sender, From d8d23fc844d7c42251a5b2d751ba7052b8323eb5 Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Fri, 20 Dec 2024 13:51:57 -0700 Subject: [PATCH 5/6] Bumped bluez-async version to bring in mtu property --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9cd7854..3ba7c53b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ tokio-stream = { version = "0.1.16", features = ["sync"] } [target.'cfg(target_os = "linux")'.dependencies] dbus = "0.9.7" -bluez-async = "0.7.2" +bluez-async = "0.8.0" [target.'cfg(target_os = "android")'.dependencies] jni = "0.19.0" From 830faff9b4a1499303bc35c994ea34043f017c89 Mon Sep 17 00:00:00 2001 From: Robby Madruga Date: Fri, 20 Dec 2024 13:52:20 -0700 Subject: [PATCH 6/6] Implemented bluez version of mtu method --- src/bluez/peripheral.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/bluez/peripheral.rs b/src/bluez/peripheral.rs index 426ff30b..84a3c149 100644 --- a/src/bluez/peripheral.rs +++ b/src/bluez/peripheral.rs @@ -138,6 +138,17 @@ impl api::Peripheral for Peripheral { self.mac_address } + fn mtu(&self) -> u16 { + let services = self.services.lock().unwrap(); + for (_, service) in services.iter() { + for (_, characteristic) in service.characteristics.iter() { + return characteristic.info.mtu.unwrap(); + } + } + + api::DEFAULT_MTU_SIZE + } + async fn properties(&self) -> Result> { let device_info = self.device_info().await?; Ok(Some(PeripheralProperties {