From 7eef2837ad49be4e40ebd9801094184a173df87a Mon Sep 17 00:00:00 2001 From: Ivan P <25914822+userepo@users.noreply.github.com> Date: Wed, 16 Sep 2026 18:53:08 -0500 Subject: [PATCH] fix(winrtble): request Coded PHY scanning only when the adapter supports it SetUseCodedPhy(true) is accepted, and Start succeeds, on adapters without Coded PHY support (e.g. Bluetooth 4.x dongles), but the scan then never delivers a single advertisement. Gate the call on BluetoothAdapter.IsLowEnergyCodedPhySupported so those adapters scan as in 0.12, and log which path was taken. Fixes #473. --- src/winrtble/adapter.rs | 5 ++++- src/winrtble/ble/watcher.rs | 29 +++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/winrtble/adapter.rs b/src/winrtble/adapter.rs index 16d0665c..3111570f 100644 --- a/src/winrtble/adapter.rs +++ b/src/winrtble/adapter.rs @@ -67,7 +67,10 @@ fn get_central_state(radio: &Radio) -> CentralState { impl Adapter { pub(crate) fn new(bluetooth_adapter: BluetoothAdapter, radio: Radio) -> Result { - let watcher = Arc::new(Mutex::new(BLEWatcher::new()?)); + let coded_phy_supported = bluetooth_adapter + .IsLowEnergyCodedPhySupported() + .unwrap_or(false); + let watcher = Arc::new(Mutex::new(BLEWatcher::new(coded_phy_supported)?)); let manager = Arc::new(AdapterManager::default()); let radio_clone = radio.clone(); diff --git a/src/winrtble/ble/watcher.rs b/src/winrtble/ble/watcher.rs index 88774a5f..c9564087 100644 --- a/src/winrtble/ble/watcher.rs +++ b/src/winrtble/ble/watcher.rs @@ -12,6 +12,7 @@ // Copyright (c) 2014 The Rust Project Developers use crate::{Error, Result, api::ScanFilter, winrtble::utils}; +use log::debug; use std::{collections::HashSet, sync::Mutex}; use windows::{Devices::Bluetooth::Advertisement::*, Foundation::TypedEventHandler, core::Ref}; @@ -24,6 +25,10 @@ pub type AdvertisementEventHandler = pub struct BLEWatcher { watcher: BluetoothLEAdvertisementWatcher, received_token: Option, + /// Whether the adapter reports Coded (long-range) PHY support. Only + /// then is `UseCodedPhy` requested: the setter succeeds on any adapter, + /// and on one without Coded PHY the scan starts but never reports. + coded_phy_supported: bool, } impl From for Error { @@ -50,12 +55,13 @@ impl MatchCache { } impl BLEWatcher { - pub fn new() -> Result { + pub fn new(coded_phy_supported: bool) -> Result { let ad = BluetoothLEAdvertisementFilter::new()?; let watcher = BluetoothLEAdvertisementWatcher::Create(&ad)?; Ok(BLEWatcher { watcher, received_token: None, + coded_phy_supported, }) } @@ -77,11 +83,22 @@ impl BLEWatcher { self.watcher .SetScanningMode(BluetoothLEScanningMode::Active)?; let _ = self.watcher.SetAllowExtendedAdvertisements(true); - // Also receive on the Coded (long-range) PHY where the adapter and - // OS support it. Only takes effect alongside extended advertisements - // (above); the error is ignored the same way, so systems without - // Coded PHY support behave exactly as before. - let _ = self.watcher.SetUseCodedPhy(true); + // Also receive on the Coded (long-range) PHY, but only when the + // adapter supports it. `SetUseCodedPhy(true)` is accepted (and + // `Start` succeeds) on adapters without Coded PHY as well, and the + // scan then delivers no advertisements at all, so the capability + // check is the guard rather than the setter's result. + if self.coded_phy_supported { + let _ = self.watcher.SetUseCodedPhy(true); + } + debug!( + "extended scanning enabled; coded PHY {}", + if self.coded_phy_supported { + "enabled" + } else { + "not supported by adapter, disabled" + } + ); // Pre-convert the filter UUIDs once so the handler closure is cheap. let filter_guids: Vec = services.iter().map(utils::to_guid).collect();