btleplug/winrtble/ble/
watcher.rs

1// btleplug Source Code File
2//
3// Copyright 2020 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7//
8// Some portions of this file are taken and/or modified from Rumble
9// (https://github.com/mwylde/rumble), using a dual MIT/Apache License under the
10// following copyright:
11//
12// Copyright (c) 2014 The Rust Project Developers
13
14use crate::{api::ScanFilter, Error, Result};
15use windows::{core::Ref, Devices::Bluetooth::Advertisement::*, Foundation::TypedEventHandler};
16
17pub type AdvertisementEventHandler =
18    Box<dyn Fn(&BluetoothLEAdvertisementReceivedEventArgs) -> windows::core::Result<()> + Send>;
19
20#[derive(Debug)]
21pub struct BLEWatcher {
22    watcher: BluetoothLEAdvertisementWatcher,
23}
24
25impl From<windows::core::Error> for Error {
26    fn from(err: windows::core::Error) -> Error {
27        Error::Other(format!("{:?}", err).into())
28    }
29}
30
31impl BLEWatcher {
32    pub fn new() -> Result<Self> {
33        let ad = BluetoothLEAdvertisementFilter::new()?;
34        let watcher = BluetoothLEAdvertisementWatcher::Create(&ad)?;
35        Ok(BLEWatcher { watcher })
36    }
37
38    pub fn start(&self, filter: ScanFilter, on_received: AdvertisementEventHandler) -> Result<()> {
39        let ScanFilter { services } = filter;
40        let ad = self.watcher.AdvertisementFilter()?.Advertisement()?;
41        let ad_services = ad.ServiceUuids()?;
42        ad_services.Clear()?;
43        for service in services {
44            ad_services.Append(windows::core::GUID::from(service.as_u128()))?;
45        }
46        self.watcher
47            .SetScanningMode(BluetoothLEScanningMode::Active)?;
48        let _ = self.watcher.SetAllowExtendedAdvertisements(true);
49        let handler: TypedEventHandler<
50            BluetoothLEAdvertisementWatcher,
51            BluetoothLEAdvertisementReceivedEventArgs,
52        > = TypedEventHandler::new(
53            move |_sender, args: Ref<BluetoothLEAdvertisementReceivedEventArgs>| {
54                if let Ok(args) = args.ok() {
55                    on_received(args)?;
56                }
57                Ok(())
58            },
59        );
60
61        self.watcher.Received(&handler)?;
62        self.watcher.Start()?;
63        Ok(())
64    }
65
66    pub fn stop(&self) -> Result<()> {
67        self.watcher.Stop()?;
68        Ok(())
69    }
70}