@@ -2,10 +2,11 @@ use std::collections::HashMap;
22
33use btleplug:: api:: bleuuid:: uuid_from_u16;
44use btleplug:: api:: {
5- Central as _, Manager as _, Peripheral as _, PeripheralProperties , ScanFilter ,
5+ Central as _, CentralEvent , Manager as _, Peripheral as _, PeripheralProperties , ScanFilter ,
66} ;
7- use btleplug:: platform:: { Adapter , Manager , Peripheral } ;
8- use tracing:: { debug, info, instrument, Level } ;
7+ use btleplug:: platform:: { Adapter , Manager , Peripheral , PeripheralId } ;
8+ use futures:: { Stream , StreamExt } ;
9+ use tracing:: { debug, info, instrument, trace, warn, Level } ;
910use uuid:: Uuid ;
1011
1112use super :: device:: FidoEndpoints ;
@@ -50,17 +51,66 @@ impl SupportedRevisions {
5051 }
5152}
5253
54+ async fn on_peripheral_service_data (
55+ adapter : & Adapter ,
56+ id : & PeripheralId ,
57+ uuids : & [ Uuid ] ,
58+ service_data : HashMap < Uuid , Vec < u8 > > ,
59+ ) -> Option < ( Peripheral , Vec < u8 > ) > {
60+ for uuid in uuids {
61+ if let Some ( service_data) = service_data. get ( uuid) {
62+ trace ! ( ?id, ?service_data, "Found service data" ) ;
63+ let Ok ( peripheral) = adapter. peripheral ( id) . await else {
64+ warn ! ( ?id, "Could not get peripheral" ) ;
65+ return None ;
66+ } ;
67+
68+ debug ! ( { ?id, ?service_data } , "Found service data for peripheral" ) ;
69+ return Some ( ( peripheral, service_data. to_owned ( ) ) ) ;
70+ }
71+ }
72+
73+ trace ! (
74+ { ?id, ?service_data } ,
75+ "Ignoring periperal as it doesn't have service data for desired UUID"
76+ ) ;
77+ None
78+ }
79+
5380#[ instrument( level = Level :: DEBUG , skip_all) ]
54- pub async fn start_discovery ( uuids : & [ Uuid ] ) -> Result < ( ) , Error > {
81+ /// Starts a discovery for devices with specific service data
82+ pub async fn start_discovery_for_service_data (
83+ uuids : Vec < Uuid > ,
84+ ) -> Result < impl Stream < Item = ( Peripheral , Vec < u8 > ) > , Error > {
5585 let adapter = get_adapter ( ) . await ?;
56- let scan_filter = ScanFilter {
57- services : uuids . to_vec ( ) ,
58- } ;
86+ let scan_filter = ScanFilter :: default ( ) ;
87+
88+ let events = adapter . events ( ) . await . or ( Err ( Error :: Unavailable ) ) ? ;
5989
6090 adapter
6191 . start_scan ( scan_filter)
6292 . await
63- . or ( Err ( Error :: ConnectionFailed ) )
93+ . or ( Err ( Error :: ConnectionFailed ) ) ?;
94+
95+ let stream = events. filter_map ( {
96+ let adapter = adapter. clone ( ) ;
97+ let uuids = uuids. clone ( ) ;
98+ move |event| {
99+ let adapter = adapter. clone ( ) ;
100+ let uuids = uuids. clone ( ) ;
101+ async move {
102+ // trace!(?event);
103+ match event {
104+ CentralEvent :: ServiceDataAdvertisement { id, service_data } => {
105+ on_peripheral_service_data ( & adapter, & id, & uuids, service_data) . await
106+ }
107+ _ => None ,
108+ }
109+ }
110+ }
111+ } ) ;
112+
113+ Ok ( stream)
64114}
65115
66116/// TODO(#86): Support multiple adapters.
@@ -84,6 +134,7 @@ async fn discover_properties(
84134 . properties ( )
85135 . await
86136 . or ( Err ( Error :: ConnectionFailed ) ) ?;
137+ trace ! ( { ?peripheral, ?properties } ) ;
87138 if let Some ( properties) = properties {
88139 result. push ( ( peripheral, properties) ) ;
89140 }
@@ -117,38 +168,20 @@ pub async fn list_fido_devices() -> Result<Vec<FidoDevice>, Error> {
117168 Ok ( with_properties)
118169}
119170
120- #[ instrument( level = Level :: DEBUG , skip_all) ]
121- pub async fn list_devices_with_service_data (
122- service_uuid : Uuid ,
123- ) -> Result < HashMap < FidoDevice , Vec < u8 > > , Error > {
124- let adapter = get_adapter ( ) . await ?;
125- let peripherals = adapter
126- . peripherals ( )
171+ pub async fn get_device ( peripheral : Peripheral ) -> Result < Option < FidoDevice > , Error > {
172+ let Some ( properties) = peripheral
173+ . properties ( )
127174 . await
128- . or ( Err ( Error :: ConnectionFailed ) ) ?;
129- for peripheral in & peripherals {
130- // TODO: parallelize this
131- peripheral
132- . discover_services ( )
133- . await
134- . or ( Err ( Error :: ConnectionFailed ) ) ?;
135- }
136- let with_properties = discover_properties ( peripherals) . await ?;
137- Ok ( with_properties
138- . into_iter ( )
139- . filter_map (
140- |( peripheral, properties) | match properties. service_data . get ( & service_uuid) {
141- Some ( service_data) => {
142- let device = FidoDevice {
143- peripheral,
144- properties : properties. to_owned ( ) ,
145- } ;
146- Some ( ( device, service_data. to_owned ( ) ) )
147- }
148- None => None ,
149- } ,
150- )
151- . collect ( ) )
175+ . or ( Err ( Error :: ConnectionFailed ) ) ?
176+ else {
177+ return Ok ( None ) ;
178+ } ;
179+
180+ let device = FidoDevice {
181+ peripheral,
182+ properties,
183+ } ;
184+ Ok ( Some ( device) )
152185}
153186
154187pub async fn supported_fido_revisions (
0 commit comments