Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<PeripheralProperties>>;
Expand Down
31 changes: 30 additions & 1 deletion src/winrtble/ble/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,37 @@ use windows::{
BluetoothCacheMode, BluetoothConnectionStatus, BluetoothLEDevice,
GenericAttributeProfile::{
GattCharacteristic, GattCommunicationStatus, GattDescriptor, GattDeviceService,
GattDeviceServicesResult,
GattDeviceServicesResult, GattSession,
},
},
Foundation::{EventRegistrationToken, TypedEventHandler},
};

pub type ConnectedEventHandler = Box<dyn Fn(bool) + Send>;
pub type MaxPduSizeChangedEventHandler = Box<dyn Fn(u16) + Send>;

pub struct BLEDevice {
device: BluetoothLEDevice,
gatt_session: GattSession,
connection_token: EventRegistrationToken,
pdu_change_token: EventRegistrationToken,
services: Vec<GattDeviceService>,
}

impl BLEDevice {
pub async fn new(
address: BDAddr,
connection_status_changed: ConnectedEventHandler,
max_pdu_size_changed: MaxPduSizeChangedEventHandler,
) -> Result<Self> {
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<BluetoothLEDevice>, _| {
if let Some(sender) = sender {
Expand All @@ -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<GattSession>, _| {
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![],
})
}
Expand Down Expand Up @@ -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);
Expand Down
34 changes: 28 additions & 6 deletions src/winrtble/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -70,6 +70,7 @@ struct Shared {
device: tokio::sync::Mutex<Option<BLEDevice>>,
adapter: Weak<AdapterManager<Peripheral>>,
address: BDAddr,
mtu: AtomicU16,
connected: AtomicBool,
ble_services: DashMap<Uuid, BLEService>,
notifications_channel: broadcast::Sender<ValueNotification>,
Expand All @@ -93,6 +94,7 @@ impl Peripheral {
adapter,
device: tokio::sync::Mutex::new(None),
address,
mtu: AtomicU16::new(23),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where does this 23 come from?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the default size of the MTU prior to negotiation. It includes the L2CAP header (4 bytes), so usable size would be 19.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'll add an initial assignment from MaxPduSize prior to the event handler registration.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a constant for it, with a comment explaining this.

connected: AtomicBool::new(false),
ble_services: DashMap::new(),
notifications_channel: broadcast_sender,
Expand Down Expand Up @@ -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<Option<PeripheralProperties>> {
Expand All @@ -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);
}
Expand All @@ -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?;

Expand Down
Loading