mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
[fp-rs] Device now holds 16bit UUID service data, collected by Adapter.
This commit is contained in:
@@ -32,4 +32,6 @@ windows = { version = "0.48", features = [
|
||||
"Devices_Enumeration",
|
||||
"Devices_Bluetooth_Advertisement",
|
||||
"Foundation",
|
||||
"Foundation_Collections",
|
||||
"Storage_Streams",
|
||||
] }
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2023 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
pub enum BleDataSection {
|
||||
ServiceData16BitUUid = 0x16,
|
||||
}
|
||||
|
||||
pub struct ServiceData<U: Copy> {
|
||||
uuid: U,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<U: Copy> ServiceData<U> {
|
||||
pub fn new(uuid: U, data: Vec<u8>) -> Self {
|
||||
ServiceData { uuid, data }
|
||||
}
|
||||
|
||||
pub fn uuid(&self) -> U {
|
||||
self.uuid
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &Vec<u8> {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::{Address, BluetoothError, PairingResult};
|
||||
use super::{Address, BluetoothError, PairingResult, ServiceData};
|
||||
|
||||
/// Concrete types implementing this trait represent Bluetooth Peripheral devices.
|
||||
/// They provide methods for retrieving device info and running device actions,
|
||||
@@ -29,4 +29,6 @@ pub trait Device: Sized {
|
||||
|
||||
/// Attempt pairing with the peripheral device.
|
||||
async fn pair(&self) -> Result<PairingResult, BluetoothError>;
|
||||
|
||||
fn service_data(&self) -> &Vec<ServiceData<u16>>;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
/// Module for shared functionality between all Bluetooth platforms.
|
||||
mod adapter;
|
||||
mod address;
|
||||
mod data;
|
||||
mod device;
|
||||
mod error;
|
||||
|
||||
pub use adapter::*;
|
||||
pub use address::*;
|
||||
pub use data::*;
|
||||
pub use device::*;
|
||||
pub use error::*;
|
||||
|
||||
@@ -51,11 +51,16 @@ use windows::{
|
||||
// (e.g. Received and Stopped events in BluetoothLEAdvertisementWatcher).
|
||||
// https://learn.microsoft.com/en-us/uwp/api/windows.foundation.typedeventhandler-2?view=winrt-22621
|
||||
Foundation::TypedEventHandler,
|
||||
|
||||
// Struct for reading data from a Windows stream, like an IVectorView.
|
||||
// https://learn.microsoft.com/en-us/uwp/api/windows.storage.streams.datareader?view=winrt-22621
|
||||
Storage::Streams::DataReader,
|
||||
};
|
||||
|
||||
use super::BleDevice;
|
||||
use crate::bluetooth::common::{
|
||||
Adapter, BleAddress, BleAddressKind, BluetoothError,
|
||||
Adapter, BleAddress, BleAddressKind, BleDataSection, BluetoothError,
|
||||
ServiceData,
|
||||
};
|
||||
|
||||
/// Struct holding the necessary fields for listening to and handling incoming
|
||||
@@ -73,6 +78,39 @@ pub struct BleAdapter {
|
||||
listener: Option<AdvListener>,
|
||||
}
|
||||
|
||||
/// Parse the advertisement's service data.
|
||||
/// Further Reading:
|
||||
/// * `BleMedium::AdvertisementReceivedHandler` under
|
||||
/// github.com/google/nearby/internal/platform/implementation/windows_ble/ble_medium.cc.
|
||||
/// * Bluetooth Core Specification Supplement, Part A, Section 1.11.
|
||||
/// * go/fast_pair_windows_data_parse.
|
||||
#[inline]
|
||||
fn get_service_data_16bit_uuid(
|
||||
event_args: &BluetoothLEAdvertisementReceivedEventArgs,
|
||||
) -> Result<Vec<ServiceData<u16>>, BluetoothError> {
|
||||
let advertisement = event_args.Advertisement()?;
|
||||
let mut service_data_vec = Vec::new();
|
||||
|
||||
// Note `service_data` is `!Send` and `!Sync`. This means processing must
|
||||
// occur in a synchronous environment (namely, this function's scope).
|
||||
// The compiler will complain if similar code is written between awaits
|
||||
// in an async function.
|
||||
for service_data in advertisement
|
||||
.GetSectionsByType(BleDataSection::ServiceData16BitUUid as u8)?
|
||||
{
|
||||
let data_reader = DataReader::FromBuffer(&service_data.Data()?)?;
|
||||
let uuid = data_reader.ReadUInt16()?;
|
||||
|
||||
let unconsumed_buffer_len =
|
||||
data_reader.UnconsumedBufferLength()? as usize;
|
||||
let mut data = vec![0u8; unconsumed_buffer_len];
|
||||
data_reader.ReadBytes(&mut data)?;
|
||||
|
||||
service_data_vec.push(ServiceData::new(uuid, data));
|
||||
}
|
||||
Ok(service_data_vec)
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Adapter for BleAdapter {
|
||||
type Device = BleDevice;
|
||||
@@ -202,13 +240,12 @@ impl Adapter for BleAdapter {
|
||||
|
||||
let kind = BleAddressKind::try_from(kind)?;
|
||||
let addr = BleAddress::new(addr, kind);
|
||||
let service_data =
|
||||
get_service_data_16bit_uuid(&event_args)?;
|
||||
|
||||
match BleDevice::new(addr).await {
|
||||
Ok(device) => break Ok(device),
|
||||
Err(err) => {
|
||||
warn!("Error creating device: {:?}", err);
|
||||
}
|
||||
}
|
||||
let device = BleDevice::new(addr, service_data).await?;
|
||||
|
||||
break Ok(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,12 +49,13 @@ use windows::{
|
||||
Foundation::TypedEventHandler,
|
||||
};
|
||||
|
||||
use crate::bluetooth::common::{Address, BleAddress, ClassicAddress, Device, BluetoothError, PairingResult};
|
||||
use crate::bluetooth::common::{Address, BleAddress, ClassicAddress, Device, ServiceData, BluetoothError, PairingResult};
|
||||
|
||||
/// Concrete type implementing `Device`, used for Windows BLE.
|
||||
pub struct BleDevice {
|
||||
inner: BluetoothLEDevice,
|
||||
addr: BleAddress,
|
||||
service_data: Vec<ServiceData<u16>>
|
||||
}
|
||||
|
||||
/// Concrete type implementing `Device`, used for Windows Bluetooth Classic.
|
||||
@@ -65,7 +66,7 @@ pub struct ClassicDevice {
|
||||
|
||||
impl BleDevice {
|
||||
/// `BleDevice` constructor.
|
||||
pub async fn new(addr: BleAddress) -> Result<Self, BluetoothError> {
|
||||
pub async fn new(addr: BleAddress, service_data: Vec<ServiceData<u16>>) -> Result<Self, BluetoothError> {
|
||||
let kind = BluetoothAddressType::from(addr.get_kind());
|
||||
let raw_addr = u64::from(addr);
|
||||
|
||||
@@ -74,7 +75,7 @@ impl BleDevice {
|
||||
)?
|
||||
.await?;
|
||||
|
||||
Ok(BleDevice { inner, addr })
|
||||
Ok(BleDevice { inner, addr, service_data })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +96,10 @@ impl Device for BleDevice {
|
||||
// `ClassicDevice::pair` directly.
|
||||
unimplemented!("BLE Pairing is currently unsupported.")
|
||||
}
|
||||
|
||||
fn service_data(&self) -> &Vec<ServiceData<u16>> {
|
||||
&self.service_data
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +174,10 @@ impl Device for ClassicDevice {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn service_data(&self) -> &Vec<ServiceData<u16>> {
|
||||
unimplemented!("Service data is currently unsupported for Classic devices.")
|
||||
}
|
||||
}
|
||||
|
||||
mod tests {
|
||||
|
||||
@@ -36,8 +36,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
// Dynamic dispatch is necessary here because `BleDevice` and
|
||||
// `ClassicDevice` share the `Device` trait (and thus must have
|
||||
// the same return type for `address()` method). This can be
|
||||
// changed if `Device` trait should exclusively define
|
||||
// cross-platform behavior.
|
||||
// changed later if `Device` trait should exclusively define
|
||||
// shared cross-platform behavior.
|
||||
let classic_addr = match addr {
|
||||
Address::Ble(ble) => ClassicAddress::try_from(ble),
|
||||
Address::Classic(_) => unreachable!(
|
||||
|
||||
Reference in New Issue
Block a user