From f7a440a85a3bf38153a595ac0462de95c407cea9 Mon Sep 17 00:00:00 2001 From: Patrick Gansterer Date: Fri, 3 Sep 2021 21:01:06 +0200 Subject: [PATCH] Add ScanFilter to Central::start_scan() --- examples/discover_adapters_peripherals.rs | 4 ++-- examples/event_driven_discovery.rs | 4 ++-- examples/lights.rs | 6 ++++-- examples/subscribe_notify_characteristic.rs | 5 ++--- src/api/mod.rs | 14 +++++++++++++- src/bluez/adapter.rs | 5 +++-- src/corebluetooth/adapter.rs | 6 +++--- src/corebluetooth/internal.rs | 11 +++++++---- src/lib.rs | 4 ++-- src/winrtble/adapter.rs | 5 +++-- 10 files changed, 41 insertions(+), 23 deletions(-) diff --git a/examples/discover_adapters_peripherals.rs b/examples/discover_adapters_peripherals.rs index 5126599f..811595fc 100644 --- a/examples/discover_adapters_peripherals.rs +++ b/examples/discover_adapters_peripherals.rs @@ -5,7 +5,7 @@ use std::error::Error; use std::time::Duration; use tokio::time; -use btleplug::api::{Central, Manager as _, Peripheral}; +use btleplug::api::{Central, Manager as _, Peripheral, ScanFilter}; use btleplug::platform::Manager; #[tokio::main] @@ -21,7 +21,7 @@ async fn main() -> Result<(), Box> { for adapter in adapter_list.iter() { println!("Starting scan..."); adapter - .start_scan() + .start_scan(ScanFilter::default()) .await .expect("Can't scan BLE adapter for connected devices..."); time::sleep(Duration::from_secs(10)).await; diff --git a/examples/event_driven_discovery.rs b/examples/event_driven_discovery.rs index ef7ace92..aff4f384 100644 --- a/examples/event_driven_discovery.rs +++ b/examples/event_driven_discovery.rs @@ -1,7 +1,7 @@ // See the "macOS permissions note" in README.md before running this on macOS // Big Sur or later. -use btleplug::api::{bleuuid::BleUuid, Central, CentralEvent, Manager as _}; +use btleplug::api::{bleuuid::BleUuid, Central, CentralEvent, Manager as _, ScanFilter}; use btleplug::platform::{Adapter, Manager}; use futures::stream::StreamExt; use std::error::Error; @@ -33,7 +33,7 @@ async fn main() -> Result<(), Box> { let mut events = central.events().await?; // start scanning for devices - central.start_scan().await?; + central.start_scan(ScanFilter::default()).await?; // Print based on whatever the event receiver outputs. Note that the event // receiver blocks, so in a real program, this should be run in its own diff --git a/examples/lights.rs b/examples/lights.rs index 76e08f59..b460f906 100644 --- a/examples/lights.rs +++ b/examples/lights.rs @@ -1,7 +1,9 @@ // See the "macOS permissions note" in README.md before running this on macOS // Big Sur or later. -use btleplug::api::{bleuuid::uuid_from_u16, Central, Manager as _, Peripheral as _, WriteType}; +use btleplug::api::{ + bleuuid::uuid_from_u16, Central, Manager as _, Peripheral as _, ScanFilter, WriteType, +}; use btleplug::platform::{Adapter, Manager, Peripheral}; use rand::{thread_rng, Rng}; use std::error::Error; @@ -43,7 +45,7 @@ async fn main() -> Result<(), Box> { .expect("Unable to find adapters."); // start scanning for devices - central.start_scan().await?; + central.start_scan(ScanFilter::default()).await?; // instead of waiting, you can use central.event_receiver() to get a channel // to listen for notifications on. time::sleep(Duration::from_secs(2)).await; diff --git a/examples/subscribe_notify_characteristic.rs b/examples/subscribe_notify_characteristic.rs index 8d8cb602..8e8526bd 100644 --- a/examples/subscribe_notify_characteristic.rs +++ b/examples/subscribe_notify_characteristic.rs @@ -1,8 +1,7 @@ // See the "macOS permissions note" in README.md before running this on macOS // Big Sur or later. -use btleplug::api::CharPropFlags; -use btleplug::api::{Central, Manager as _, Peripheral}; +use btleplug::api::{Central, CharPropFlags, Manager as _, Peripheral, ScanFilter}; use btleplug::platform::Manager; use futures::stream::StreamExt; use std::error::Error; @@ -26,7 +25,7 @@ async fn main() -> Result<(), Box> { for adapter in adapter_list.iter() { println!("Starting scan..."); adapter - .start_scan() + .start_scan(ScanFilter::default()) .await .expect("Can't scan BLE adapter for connected devices..."); time::sleep(Duration::from_secs(2)).await; diff --git a/src/api/mod.rs b/src/api/mod.rs index fbc92d84..809215f8 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -180,6 +180,14 @@ pub struct PeripheralProperties { pub services: Vec, } +/// The filter used when scanning for BLE devices. +#[derive(Clone, Debug, Default, Eq, PartialEq)] +pub struct ScanFilter { + /// If the filter contains at least one service UUID, only devices supporting at least one of + /// the given services will be available. + pub services: Vec, +} + /// The type of write operation to use. #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum WriteType { @@ -299,7 +307,11 @@ pub trait Central: Send + Sync + Clone { /// Starts a scan for BLE devices. This scan will generally continue until explicitly stopped, /// although this may depend on your Bluetooth adapter. Discovered devices will be announced /// to subscribers of `events` and will be available via `peripherals()`. - async fn start_scan(&self) -> Result<()>; + /// The filter can be used to scan only for specific devices. While some implementations might + /// ignore (parts of) the filter and make additional devices available, other implementations + /// might require at least one filter for security reasons. Cross-platform code should provide + /// a filter, but must be able to handle devices, which do not fit into the filter. + async fn start_scan(&self, filter: ScanFilter) -> Result<()>; /// Stops scanning for BLE devices. async fn stop_scan(&self) -> Result<()>; diff --git a/src/bluez/adapter.rs b/src/bluez/adapter.rs index 25c60562..abdf0a08 100644 --- a/src/bluez/adapter.rs +++ b/src/bluez/adapter.rs @@ -1,5 +1,5 @@ use super::peripheral::{Peripheral, PeripheralId}; -use crate::api::{BDAddr, Central, CentralEvent}; +use crate::api::{BDAddr, Central, CentralEvent, ScanFilter}; use crate::{Error, Result}; use async_trait::async_trait; use bluez_async::{ @@ -46,8 +46,9 @@ impl Central for Adapter { Ok(Box::pin(initial_events.chain(events))) } - async fn start_scan(&self) -> Result<()> { + async fn start_scan(&self, filter: ScanFilter) -> Result<()> { let filter = DiscoveryFilter { + service_uuids: filter.services, transport: Some(Transport::Auto), ..Default::default() }; diff --git a/src/corebluetooth/adapter.rs b/src/corebluetooth/adapter.rs index c6ea8dd5..8a641fab 100644 --- a/src/corebluetooth/adapter.rs +++ b/src/corebluetooth/adapter.rs @@ -1,6 +1,6 @@ use super::internal::{run_corebluetooth_thread, CoreBluetoothEvent, CoreBluetoothMessage}; use super::peripheral::{Peripheral, PeripheralId}; -use crate::api::{BDAddr, Central, CentralEvent}; +use crate::api::{BDAddr, Central, CentralEvent, ScanFilter}; use crate::common::adapter_manager::AdapterManager; use crate::{Error, Result}; use async_trait::async_trait; @@ -87,10 +87,10 @@ impl Central for Adapter { Ok(self.manager.event_stream()) } - async fn start_scan(&self) -> Result<()> { + async fn start_scan(&self, filter: ScanFilter) -> Result<()> { self.sender .to_owned() - .send(CoreBluetoothMessage::StartScanning) + .send(CoreBluetoothMessage::StartScanning { filter }) .await?; Ok(()) } diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index 9f45c4bf..b81212ba 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -17,7 +17,7 @@ use super::{ future::{BtlePlugFuture, BtlePlugFutureStateShared}, utils::{core_bluetooth::cbuuid_to_uuid, nsstring::nsstring_to_string, nsuuid_to_uuid}, }; -use crate::api::{CharPropFlags, Characteristic, Service, WriteType}; +use crate::api::{CharPropFlags, Characteristic, ScanFilter, Service, WriteType}; use crate::Error; use futures::channel::mpsc::{self, Receiver, Sender}; use futures::select; @@ -258,7 +258,9 @@ impl Debug for CoreBluetoothInternal { #[derive(Debug)] pub enum CoreBluetoothMessage { - StartScanning, + StartScanning { + filter: ScanFilter, + }, StopScanning, ConnectDevice { peripheral_uuid: Uuid, @@ -762,7 +764,7 @@ impl CoreBluetoothInternal { adapter_msg = self.message_receiver.select_next_some() => { trace!("Adapter message!"); match adapter_msg { - CoreBluetoothMessage::StartScanning => self.start_discovery(), + CoreBluetoothMessage::StartScanning{filter} => self.start_discovery(filter), CoreBluetoothMessage::StopScanning => self.stop_discovery(), CoreBluetoothMessage::ConnectDevice{peripheral_uuid, future} => { trace!("got connectdevice msg!"); @@ -793,7 +795,7 @@ impl CoreBluetoothInternal { } } - fn start_discovery(&mut self) { + fn start_discovery(&mut self, _filter: ScanFilter) { trace!("BluetoothAdapter::start_discovery"); let options = ns::mutabledictionary(); // NOTE: If duplicates are not allowed then a peripheral will not show @@ -801,6 +803,7 @@ impl CoreBluetoothInternal { ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(YES), unsafe { cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY }); + // TODO: set cb::CBCENTRALMANAGERSCANOPTIONSOLICITEDSERVICEUUIDSKEY with filter.services cb::centralmanager_scanforperipherals_options(*self.manager, options); } diff --git a/src/lib.rs b/src/lib.rs index 6c7b4d61..914e1148 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ //! An example of how to use the library to control some BLE smart lights: //! //! ```rust,no_run -//! use btleplug::api::{bleuuid::uuid_from_u16, Central, Manager as _, Peripheral as _, WriteType}; +//! use btleplug::api::{bleuuid::uuid_from_u16, Central, Manager as _, Peripheral as _, ScanFilter, WriteType}; //! use btleplug::platform::{Adapter, Manager, Peripheral}; //! use rand::{Rng, thread_rng}; //! use std::error::Error; @@ -40,7 +40,7 @@ //! let central = adapters.into_iter().nth(0).unwrap(); //! //! // start scanning for devices -//! central.start_scan().await?; +//! central.start_scan(ScanFilter::default()).await?; //! // instead of waiting, you can use central.event_receiver() to fetch a channel and //! // be notified of new devices //! time::sleep(Duration::from_secs(2)).await; diff --git a/src/winrtble/adapter.rs b/src/winrtble/adapter.rs index 34792ed9..bb7d25c4 100644 --- a/src/winrtble/adapter.rs +++ b/src/winrtble/adapter.rs @@ -13,7 +13,7 @@ use super::{ble::watcher::BLEWatcher, peripheral::Peripheral, peripheral::PeripheralId}; use crate::{ - api::{BDAddr, Central, CentralEvent}, + api::{BDAddr, Central, CentralEvent, ScanFilter}, common::adapter_manager::AdapterManager, Error, Result, }; @@ -55,7 +55,8 @@ impl Central for Adapter { Ok(self.manager.event_stream()) } - async fn start_scan(&self) -> Result<()> { + async fn start_scan(&self, _filter: ScanFilter) -> Result<()> { + // TODO: implement filter let watcher = self.watcher.lock().unwrap(); let manager = self.manager.clone(); watcher.start(Box::new(move |args| {