Skip to content

Commit

Permalink
chore: Add type PeripheralId
Browse files Browse the repository at this point in the history
Some platforms do not use a BDAddr to identify a specific device. This new
type allows different platforms to use their own identifier.
  • Loading branch information
paroga committed Aug 28, 2021
1 parent 8719d7c commit 8cdbc9a
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 107 deletions.
30 changes: 12 additions & 18 deletions examples/event_driven_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,37 +40,31 @@ async fn main() -> Result<(), Box<dyn Error>> {
// thread (not task, as this library does not yet use async channels).
while let Some(event) = events.next().await {
match event {
CentralEvent::DeviceDiscovered(bd_addr) => {
println!("DeviceDiscovered: {:?}", bd_addr);
CentralEvent::DeviceDiscovered(id) => {
println!("DeviceDiscovered: {:?}", id);
}
CentralEvent::DeviceConnected(bd_addr) => {
println!("DeviceConnected: {:?}", bd_addr);
CentralEvent::DeviceConnected(id) => {
println!("DeviceConnected: {:?}", id);
}
CentralEvent::DeviceDisconnected(bd_addr) => {
println!("DeviceDisconnected: {:?}", bd_addr);
CentralEvent::DeviceDisconnected(id) => {
println!("DeviceDisconnected: {:?}", id);
}
CentralEvent::ManufacturerDataAdvertisement {
address,
id,
manufacturer_data,
} => {
println!(
"ManufacturerDataAdvertisement: {:?}, {:?}",
address, manufacturer_data
id, manufacturer_data
);
}
CentralEvent::ServiceDataAdvertisement {
address,
service_data,
} => {
println!(
"ServiceDataAdvertisement: {:?}, {:?}",
address, service_data
);
CentralEvent::ServiceDataAdvertisement { id, service_data } => {
println!("ServiceDataAdvertisement: {:?}, {:?}", id, service_data);
}
CentralEvent::ServicesAdvertisement { address, services } => {
CentralEvent::ServicesAdvertisement { id, services } => {
let services: Vec<String> =
services.into_iter().map(|s| s.to_short_string()).collect();
println!("ServicesAdvertisement: {:?}, {:?}", address, services);
println!("ServicesAdvertisement: {:?}, {:?}", id, services);
}
_ => {}
}
Expand Down
21 changes: 13 additions & 8 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ use uuid::Uuid;

pub use self::bdaddr::{BDAddr, ParseBDAddrError};

use crate::platform::PeripheralId;

#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
Expand Down Expand Up @@ -179,6 +181,9 @@ pub enum WriteType {
/// as well as functions for communication.
#[async_trait]
pub trait Peripheral: Send + Sync + Clone + Debug {
/// Returns the unique identifier of the peripheral.
fn id(&self) -> PeripheralId;

/// Returns the MAC address of the peripheral.
fn address(&self) -> BDAddr;

Expand Down Expand Up @@ -237,23 +242,23 @@ pub trait Peripheral: Send + Sync + Clone + Debug {
)]
#[derive(Debug, Clone)]
pub enum CentralEvent {
DeviceDiscovered(BDAddr),
DeviceUpdated(BDAddr),
DeviceConnected(BDAddr),
DeviceDisconnected(BDAddr),
DeviceDiscovered(PeripheralId),
DeviceUpdated(PeripheralId),
DeviceConnected(PeripheralId),
DeviceDisconnected(PeripheralId),
/// Emitted when a Manufacturer Data advertisement has been received from a device
ManufacturerDataAdvertisement {
address: BDAddr,
id: PeripheralId,
manufacturer_data: HashMap<u16, Vec<u8>>,
},
/// Emitted when a Service Data advertisement has been received from a device
ServiceDataAdvertisement {
address: BDAddr,
id: PeripheralId,
service_data: HashMap<Uuid, Vec<u8>>,
},
/// Emitted when the advertised services for a device has been updated
ServicesAdvertisement {
address: BDAddr,
id: PeripheralId,
services: Vec<Uuid>,
},
}
Expand Down Expand Up @@ -281,7 +286,7 @@ pub trait Central: Send + Sync + Clone {
async fn peripherals(&self) -> Result<Vec<Self::Peripheral>>;

/// Returns a particular [`Peripheral`] by its address if it has been discovered.
async fn peripheral(&self, address: BDAddr) -> Result<Self::Peripheral>;
async fn peripheral(&self, id: PeripheralId) -> Result<Self::Peripheral>;

/// Add a [`Peripheral`] from a MAC address without a scan result. Not supported on all Bluetooth systems.
async fn add_peripheral(&self, address: BDAddr) -> Result<Self::Peripheral>;
Expand Down
14 changes: 7 additions & 7 deletions src/bluez/adapter.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::peripheral::Peripheral;
use super::peripheral::{Peripheral, PeripheralId};
use crate::api::{BDAddr, Central, CentralEvent};
use crate::{Error, Result};
use async_trait::async_trait;
Expand Down Expand Up @@ -37,7 +37,7 @@ impl Central for Adapter {
let initial_events = stream::iter(
devices
.into_iter()
.map(|device| CentralEvent::DeviceDiscovered(BDAddr::from(&device.mac_address))),
.map(|device| CentralEvent::DeviceDiscovered((&device.mac_address).into())),
);

let session = self.session.clone();
Expand Down Expand Up @@ -68,12 +68,12 @@ impl Central for Adapter {
.collect())
}

async fn peripheral(&self, address: BDAddr) -> Result<Peripheral> {
async fn peripheral(&self, id: PeripheralId) -> Result<Peripheral> {
let devices = self.session.get_devices().await?;
devices
.into_iter()
.find_map(|device| {
if BDAddr::from(&device.mac_address) == address {
if PeripheralId::from(&device.mac_address) == id {
Some(Peripheral::new(self.session.clone(), device))
} else {
None
Expand Down Expand Up @@ -130,7 +130,7 @@ async fn central_event(event: BluetoothEvent, session: BluetoothSession) -> Opti
} => {
let device = session.get_device_info(&id).await.ok()?;
Some(CentralEvent::ManufacturerDataAdvertisement {
address: (&device.mac_address).into(),
id: (&device.mac_address).into(),
manufacturer_data,
})
}
Expand All @@ -140,7 +140,7 @@ async fn central_event(event: BluetoothEvent, session: BluetoothSession) -> Opti
} => {
let device = session.get_device_info(&id).await.ok()?;
Some(CentralEvent::ServiceDataAdvertisement {
address: (&device.mac_address).into(),
id: (&device.mac_address).into(),
service_data,
})
}
Expand All @@ -150,7 +150,7 @@ async fn central_event(event: BluetoothEvent, session: BluetoothSession) -> Opti
} => {
let device = session.get_device_info(&id).await.ok()?;
Some(CentralEvent::ServicesAdvertisement {
address: (&device.mac_address).into(),
id: (&device.mac_address).into(),
services,
})
}
Expand Down
22 changes: 22 additions & 0 deletions src/bluez/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ use bluez_async::{
};
use futures::future::ready;
use futures::stream::{Stream, StreamExt};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
use serde_cr as serde;
use std::collections::BTreeSet;
use std::pin::Pin;
use std::sync::{Arc, Mutex};
Expand All @@ -15,6 +19,14 @@ use crate::api::{
};
use crate::{Error, Result};

#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_cr")
)]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct PeripheralId(BDAddr);

/// Implementation of [api::Peripheral](crate::api::Peripheral).
#[derive(Clone, Debug)]
pub struct Peripheral {
Expand Down Expand Up @@ -58,6 +70,10 @@ impl Peripheral {

#[async_trait]
impl api::Peripheral for Peripheral {
fn id(&self) -> PeripheralId {
PeripheralId(self.address())
}

fn address(&self) -> BDAddr {
self.mac_address
}
Expand Down Expand Up @@ -192,6 +208,12 @@ impl From<&MacAddress> for BDAddr {
}
}

impl From<&MacAddress> for PeripheralId {
fn from(mac_address: &MacAddress) -> Self {
PeripheralId(BDAddr::from(mac_address))
}
}

impl From<bluez_async::AddressType> for AddressType {
fn from(address_type: bluez_async::AddressType) -> Self {
match address_type {
Expand Down
24 changes: 12 additions & 12 deletions src/common/adapter_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
// following copyright:
//
// Copyright (c) 2014 The Rust Project Developers
use crate::api::{BDAddr, CentralEvent, Peripheral};
use crate::api::{CentralEvent, Peripheral};
use crate::platform::PeripheralId;
use dashmap::{mapref::one::RefMut, DashMap};
use futures::stream::{Stream, StreamExt};
use log::trace;
Expand All @@ -30,7 +31,7 @@ where

#[derive(Debug)]
struct Shared<PeripheralType> {
peripherals: DashMap<BDAddr, PeripheralType>,
peripherals: DashMap<PeripheralId, PeripheralType>,
events_channel: broadcast::Sender<CentralEvent>,
}

Expand All @@ -52,8 +53,8 @@ where
{
pub fn emit(&self, event: CentralEvent) {
match event {
CentralEvent::DeviceDisconnected(ref addr) => {
self.shared.peripherals.remove(addr);
CentralEvent::DeviceDisconnected(ref id) => {
self.shared.peripherals.remove(id);
}
_ => {}
}
Expand All @@ -74,13 +75,12 @@ where
}))
}

pub fn add_peripheral(&self, addr: BDAddr, peripheral: PeripheralType) {
pub fn add_peripheral(&self, peripheral: PeripheralType) {
assert!(
!self.shared.peripherals.contains_key(&addr),
!self.shared.peripherals.contains_key(&peripheral.id()),
"Adding a peripheral that's already in the map."
);
assert_eq!(peripheral.address(), addr, "Device has unexpected address."); // TODO remove addr argument
self.shared.peripherals.insert(addr, peripheral);
self.shared.peripherals.insert(peripheral.id(), peripheral);
}

pub fn peripherals(&self) -> Vec<PeripheralType> {
Expand All @@ -91,14 +91,14 @@ where
.collect()
}

pub fn peripheral_mut(&self, address: BDAddr) -> Option<RefMut<BDAddr, PeripheralType>> {
self.shared.peripherals.get_mut(&address)
pub fn peripheral_mut(&self, id: PeripheralId) -> Option<RefMut<PeripheralId, PeripheralType>> {
self.shared.peripherals.get_mut(&id)
}

pub fn peripheral(&self, address: BDAddr) -> Option<PeripheralType> {
pub fn peripheral(&self, id: PeripheralId) -> Option<PeripheralType> {
self.shared
.peripherals
.get(&address)
.get(&id)
.map(|val| val.value().clone())
}
}
42 changes: 14 additions & 28 deletions src/corebluetooth/adapter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::internal::{run_corebluetooth_thread, CoreBluetoothEvent, CoreBluetoothMessage};
use super::peripheral::Peripheral;
use super::peripheral::{Peripheral, PeripheralId};
use crate::api::{BDAddr, Central, CentralEvent};
use crate::common::adapter_manager::AdapterManager;
use crate::{Error, Result};
Expand All @@ -19,11 +19,6 @@ pub struct Adapter {
sender: Sender<CoreBluetoothMessage>,
}

pub(crate) fn uuid_to_bdaddr(uuid: &str) -> BDAddr {
let b: [u8; 6] = uuid.as_bytes()[0..6].try_into().unwrap();
BDAddr::try_from(b).unwrap()
}

impl Adapter {
pub(crate) async fn new() -> Result<Self> {
let (sender, mut receiver) = mpsc::channel(256);
Expand Down Expand Up @@ -53,31 +48,24 @@ impl Adapter {
name,
event_receiver,
} => {
// TODO Gotta change uuid into a BDAddr for now. Expand
// library identifier type. :(
let id = uuid_to_bdaddr(&uuid.to_string());
manager_clone.add_peripheral(
id,
Peripheral::new(
uuid,
name,
manager_clone.clone(),
event_receiver,
adapter_sender_clone.clone(),
),
);
manager_clone.emit(CentralEvent::DeviceDiscovered(id));
manager_clone.add_peripheral(Peripheral::new(
uuid,
name,
manager_clone.clone(),
event_receiver,
adapter_sender_clone.clone(),
));
manager_clone.emit(CentralEvent::DeviceDiscovered(uuid.into()));
}
CoreBluetoothEvent::DeviceUpdated { uuid, name } => {
let id = uuid_to_bdaddr(&uuid.to_string());
let id = uuid.into();
if let Some(entry) = manager_clone.peripheral_mut(id) {
entry.value().update_name(&name);
manager_clone.emit(CentralEvent::DeviceUpdated(id));
manager_clone.emit(CentralEvent::DeviceUpdated(uuid.into()));
}
}
CoreBluetoothEvent::DeviceDisconnected { uuid } => {
let id = uuid_to_bdaddr(&uuid.to_string());
manager_clone.emit(CentralEvent::DeviceDisconnected(id));
manager_clone.emit(CentralEvent::DeviceDisconnected(uuid.into()));
}
_ => {}
}
Expand Down Expand Up @@ -119,10 +107,8 @@ impl Central for Adapter {
Ok(self.manager.peripherals())
}

async fn peripheral(&self, address: BDAddr) -> Result<Peripheral> {
self.manager
.peripheral(address)
.ok_or(Error::DeviceNotFound)
async fn peripheral(&self, id: PeripheralId) -> Result<Peripheral> {
self.manager.peripheral(id).ok_or(Error::DeviceNotFound)
}

async fn add_peripheral(&self, _address: BDAddr) -> Result<Peripheral> {
Expand Down
Loading

0 comments on commit 8cdbc9a

Please sign in to comment.