Skip to content

Commit

Permalink
Fix disconnect when using the winrt backend.
Browse files Browse the repository at this point in the history
You must explicitly disconnect from each service before disconnecting from the device. Otherwise, Windows does not seem to fully disconnect the device internally.

See https://stackoverflow.com/questions/39599252/windows-ble-uwp-disconnect for similar issues.
  • Loading branch information
TristonJ authored and qdot committed Aug 24, 2023
1 parent fd3f092 commit 1ae52f4
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 7 deletions.
16 changes: 12 additions & 4 deletions src/winrtble/ble/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub type ConnectedEventHandler = Box<dyn Fn(bool) + Send>;
pub struct BLEDevice {
device: BluetoothLEDevice,
connection_token: EventRegistrationToken,
services: Vec<GattDeviceService>,
}

impl BLEDevice {
Expand Down Expand Up @@ -59,6 +60,7 @@ impl BLEDevice {
Ok(BLEDevice {
device,
connection_token,
services: vec![],
})
}

Expand Down Expand Up @@ -132,7 +134,7 @@ impl BLEDevice {
}
}

pub async fn discover_services(&self) -> Result<Vec<GattDeviceService>> {
pub async fn discover_services(&mut self) -> Result<&[GattDeviceService]> {
let winrt_error = |e| Error::Other(format!("{:?}", e).into());
let service_result = self.get_gatt_services(BluetoothCacheMode::Cached).await?;
let status = service_result.Status().map_err(winrt_error)?;
Expand All @@ -144,10 +146,10 @@ impl BLEDevice {
.map_err(winrt_error)?
.into_iter()
.collect();
debug!("services {:?}", services.len());
return Ok(services);
self.services = services;
debug!("services {:?}", self.services.len());
}
Ok(Vec::new())
Ok(self.services.as_slice())
}
}

Expand All @@ -160,6 +162,12 @@ impl Drop for BLEDevice {
debug!("Drop:remove_connection_status_changed {:?}", err);
}

self.services.iter().for_each(|service| {
if let Err(err) = service.Close() {
debug!("Drop:remove_gatt_Service {:?}", err);
}
});

let result = self.device.Close();
if let Err(err) = result {
debug!("Drop:close {:?}", err);
Expand Down
9 changes: 6 additions & 3 deletions src/winrtble/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,9 @@ impl ApiPeripheral for Peripheral {

/// Terminates a connection to the device. This is a synchronous operation.
async fn disconnect(&self) -> Result<()> {
// We need to clear the services because if this device is re-connected,
// the cached service objects will no longer be valid (they must be refreshed).
self.shared.ble_services.clear();
let mut device = self.shared.device.lock().await;
*device = None;
self.shared.connected.store(false, Ordering::Relaxed);
Expand All @@ -400,10 +403,10 @@ impl ApiPeripheral for Peripheral {

/// Discovers all characteristics for the device. This is a synchronous operation.
async fn discover_services(&self) -> Result<()> {
let device = self.shared.device.lock().await;
if let Some(ref device) = *device {
let mut device = self.shared.device.lock().await;
if let Some(ref mut device) = *device {
let gatt_services = device.discover_services().await?;
for service in &gatt_services {
for service in gatt_services {
let uuid = utils::to_uuid(&service.Uuid().unwrap());
if !self.shared.ble_services.contains_key(&uuid) {
match BLEDevice::get_characteristics(&service).await {
Expand Down

0 comments on commit 1ae52f4

Please sign in to comment.