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::{Devices::Bluetooth::Advertisement::*, Foundation::TypedEventHandler};
16
17pub type AdvertismentEventHandler = Box<dyn Fn(&BluetoothLEAdvertisementReceivedEventArgs) + Send>;
18
19pub struct BLEWatcher {
20    watcher: BluetoothLEAdvertisementWatcher,
21}
22
23impl From<windows::core::Error> for Error {
24    fn from(err: windows::core::Error) -> Error {
25        Error::Other(format!("{:?}", err).into())
26    }
27}
28
29impl BLEWatcher {
30    pub fn new() -> Self {
31        let ad = BluetoothLEAdvertisementFilter::new().unwrap();
32        let watcher = BluetoothLEAdvertisementWatcher::Create(&ad).unwrap();
33        BLEWatcher { watcher }
34    }
35
36    pub fn start(&self, filter: ScanFilter, on_received: AdvertismentEventHandler) -> Result<()> {
37        let ScanFilter { services } = filter;
38        let ad = self
39            .watcher
40            .AdvertisementFilter()
41            .unwrap()
42            .Advertisement()
43            .unwrap();
44        let ad_services = ad.ServiceUuids().unwrap();
45        ad_services.Clear().unwrap();
46        for service in services {
47            ad_services
48                .Append(windows::core::GUID::from(service.as_u128()))
49                .unwrap();
50        }
51        self.watcher
52            .SetScanningMode(BluetoothLEScanningMode::Active)
53            .unwrap();
54        self.watcher.SetAllowExtendedAdvertisements(true)?;
55        let handler: TypedEventHandler<
56            BluetoothLEAdvertisementWatcher,
57            BluetoothLEAdvertisementReceivedEventArgs,
58        > = TypedEventHandler::new(
59            move |_sender, args: &Option<BluetoothLEAdvertisementReceivedEventArgs>| {
60                if let Some(args) = args {
61                    on_received(args);
62                }
63                Ok(())
64            },
65        );
66
67        self.watcher.Received(&handler)?;
68        self.watcher.Start()?;
69        Ok(())
70    }
71
72    pub fn stop(&self) -> Result<()> {
73        self.watcher.Stop()?;
74        Ok(())
75    }
76}