| 36 | } |
| 37 | |
| 38 | pub fn start(&self, filter: ScanFilter, on_received: AdvertisementEventHandler) -> Result<()> { |
| 39 | let ScanFilter { services } = filter; |
| 40 | |
| 41 | // Clear any OS-level service UUID filter from a previous scan. |
| 42 | // We intentionally do NOT set service UUIDs on the OS filter: on some |
| 43 | // Windows BLE drivers the 128-bit UUID filter silently drops matching |
| 44 | // advertisements. Software filtering in the handler is used instead. |
| 45 | let ad = self.watcher.AdvertisementFilter()?.Advertisement()?; |
| 46 | ad.ServiceUuids()?.Clear()?; |
| 47 | |
| 48 | self.watcher |
| 49 | .SetScanningMode(BluetoothLEScanningMode::Active)?; |
| 50 | let _ = self.watcher.SetAllowExtendedAdvertisements(true); |
| 51 | |
| 52 | // Pre-convert the filter UUIDs once so the handler closure is cheap. |
| 53 | let filter_guids: Vec<windows::core::GUID> = services.iter().map(utils::to_guid).collect(); |
| 54 | |
| 55 | let handler: TypedEventHandler< |
| 56 | BluetoothLEAdvertisementWatcher, |
| 57 | BluetoothLEAdvertisementReceivedEventArgs, |
| 58 | > = TypedEventHandler::new( |
| 59 | move |_sender, args: Ref<BluetoothLEAdvertisementReceivedEventArgs>| { |
| 60 | if let Ok(args) = args.ok() { |
| 61 | // Software service-UUID filter. |
| 62 | if !filter_guids.is_empty() { |
| 63 | if let Ok(ad) = args.Advertisement() { |
| 64 | if let Ok(ad_uuids) = ad.ServiceUuids() { |
| 65 | let count = ad_uuids.Size().unwrap_or(0); |
| 66 | let advertised: Vec<windows::core::GUID> = |
| 67 | (0..count).filter_map(|i| ad_uuids.GetAt(i).ok()).collect(); |
| 68 | let all_present = |
| 69 | filter_guids.iter().all(|g| advertised.contains(g)); |
| 70 | if !all_present { |
| 71 | return Ok(()); |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | } |
| 76 | on_received(args)?; |
| 77 | } |
| 78 | Ok(()) |
| 79 | }, |
| 80 | ); |
| 81 | |
| 82 | self.watcher.Received(&handler)?; |
| 83 | self.watcher.Start()?; |
| 84 | Ok(()) |
| 85 | } |
| 86 | |
| 87 | pub fn stop(&self) -> Result<()> { |
| 88 | self.watcher.Stop()?; |