Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,12 @@ objc2-core-bluetooth = { version = "0.2.2", default-features = false, features =
] }

[target.'cfg(target_os = "windows")'.dependencies]
windows = { version = "0.57.0", features = ["Devices_Bluetooth", "Devices_Bluetooth_GenericAttributeProfile", "Devices_Bluetooth_Advertisement", "Devices_Radios", "Foundation_Collections", "Foundation", "Storage_Streams"] }
windows = { version = "0.61", features = ["Devices_Bluetooth", "Devices_Bluetooth_GenericAttributeProfile", "Devices_Bluetooth_Advertisement", "Devices_Radios", "Foundation_Collections", "Foundation", "Storage_Streams"] }

[dev-dependencies]
rand = "0.8.5"
rand = "0.9"
pretty_env_logger = "0.5.0"
tokio = { version = "1.42.0", features = ["macros", "rt", "rt-multi-thread"] }
serde_json = "1.0.134"
toml = "0.8.19"
anyhow = "1"
3 changes: 1 addition & 2 deletions examples/discover_adapters_peripherals.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
// See the "macOS permissions note" in README.md before running this on macOS
// Big Sur or later.

use std::error::Error;
use std::time::Duration;
use tokio::time;

use btleplug::api::{Central, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
async fn main() -> anyhow::Result<()> {
pretty_env_logger::init();

let manager = Manager::new().await?;
Expand Down
3 changes: 1 addition & 2 deletions examples/event_driven_discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,14 @@ use btleplug::api::{
};
use btleplug::platform::{Adapter, Manager};
use futures::stream::StreamExt;
use std::error::Error;

async fn get_central(manager: &Manager) -> Adapter {
let adapters = manager.adapters().await.unwrap();
adapters.into_iter().nth(0).unwrap()
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
async fn main() -> anyhow::Result<()> {
pretty_env_logger::init();

let manager = Manager::new().await?;
Expand Down
9 changes: 4 additions & 5 deletions examples/lights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ 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;
use rand::{rng, Rng};
use std::time::Duration;
use uuid::Uuid;

Expand All @@ -30,7 +29,7 @@ async fn find_light(central: &Adapter) -> Option<Peripheral> {
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
async fn main() -> anyhow::Result<()> {
pretty_env_logger::init();

let manager = Manager::new().await.unwrap();
Expand Down Expand Up @@ -67,9 +66,9 @@ async fn main() -> Result<(), Box<dyn Error>> {
.expect("Unable to find characterics");

// dance party
let mut rng = thread_rng();
let mut rng = rng();
for _ in 0..20 {
let color_cmd = vec![0x56, rng.gen(), rng.gen(), rng.gen(), 0x00, 0xF0, 0xAA];
let color_cmd = vec![0x56, rng.random(), rng.random(), rng.random(), 0x00, 0xF0, 0xAA];
light
.write(&cmd_char, &color_cmd, WriteType::WithoutResponse)
.await?;
Expand Down
3 changes: 1 addition & 2 deletions examples/subscribe_notify_characteristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
use btleplug::api::{Central, CharPropFlags, Manager as _, Peripheral, ScanFilter};
use btleplug::platform::Manager;
use futures::stream::StreamExt;
use std::error::Error;
use std::time::Duration;
use tokio::time;
use uuid::Uuid;
Expand All @@ -15,7 +14,7 @@ const PERIPHERAL_NAME_MATCH_FILTER: &str = "Neuro";
const NOTIFY_CHARACTERISTIC_UUID: Uuid = Uuid::from_u128(0x6e400002_b534_f393_67a9_e50e24dccA9e);

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
async fn main() -> anyhow::Result<()> {
pretty_env_logger::init();

let manager = Manager::new().await?;
Expand Down
9 changes: 6 additions & 3 deletions src/bluez/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ impl Peripheral {
}

fn characteristic_info(&self, characteristic: &Characteristic) -> Result<CharacteristicInfo> {
let services = self.services.lock().unwrap();
let services = self.services.lock()
.map_err(Into::<Error>::into)?;
get_characteristic(
&services,
&characteristic.service_uuid,
Expand All @@ -108,7 +109,8 @@ impl Peripheral {
}

fn descriptor_info(&self, descriptor: &Descriptor) -> Result<DescriptorInfo> {
let services = self.services.lock().unwrap();
let services = self.services.lock()
.map_err(Into::<Error>::into)?;
let characteristic = get_characteristic(
&services,
&descriptor.service_uuid,
Expand Down Expand Up @@ -222,7 +224,8 @@ impl api::Peripheral for Peripheral {
},
);
}
*self.services.lock().unwrap() = services_internal;
*(self.services.lock()
.map_err(Into::<Error>::into)?) = services_internal;
Ok(())
}

Expand Down
13 changes: 11 additions & 2 deletions src/corebluetooth/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,13 @@ impl api::Peripheral for Peripheral {
}

async fn properties(&self) -> Result<Option<PeripheralProperties>> {
Ok(Some(self.shared.properties.lock().unwrap().clone()))
Ok(Some(
self.shared
.properties
.lock()
.map_err(Into::<Error>::into)?
.clone()
))
}

fn services(&self) -> BTreeSet<Service> {
Expand Down Expand Up @@ -246,7 +252,10 @@ impl api::Peripheral for Peripheral {
.await?;
match fut.await {
CoreBluetoothReply::Connected(services) => {
*(self.shared.services.lock().unwrap()) = services;
*(self.shared
.services
.lock()
.map_err(Into::<Error>::into)?) = services;
self.shared
.emit_event(CentralEvent::DeviceConnected(self.shared.uuid.into()));
}
Expand Down
6 changes: 4 additions & 2 deletions src/droidplug/peripheral.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,8 @@ impl api::Peripheral for Peripheral {
}

async fn properties(&self) -> Result<Option<PeripheralProperties>> {
let guard = self.shared.lock().unwrap();
let guard = self.shared.lock()
.map_err(Into::<Error>::into)?;
Ok((&guard.properties).clone())
}

Expand Down Expand Up @@ -303,7 +304,8 @@ impl api::Peripheral for Peripheral {
characteristics,
})
}
let mut guard = self.shared.lock().unwrap();
let mut guard = self.shared.lock()
.map_err(Into::<Error>::into)?;
guard.services = BTreeSet::from_iter(peripheral_services.clone());
guard.characteristics = BTreeSet::from_iter(peripheral_characteristics.clone());
Ok(())
Expand Down
13 changes: 10 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! ```rust,no_run
//! 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 rand::{Rng, rng};
//! use std::error::Error;
//! use std::thread;
//! use std::time::Duration;
Expand Down Expand Up @@ -59,9 +59,9 @@
//! let cmd_char = chars.iter().find(|c| c.uuid == LIGHT_CHARACTERISTIC_UUID).unwrap();
//!
//! // dance party
//! let mut rng = thread_rng();
//! let mut rng = rng();
//! for _ in 0..20 {
//! let color_cmd = vec![0x56, rng.gen(), rng.gen(), rng.gen(), 0x00, 0xF0, 0xAA];
//! let color_cmd = vec![0x56, rng.random(), rng.random(), rng.random(), 0x00, 0xF0, 0xAA];
//! light.write(&cmd_char, &color_cmd, WriteType::WithoutResponse).await?;
//! time::sleep(Duration::from_millis(200)).await;
//! }
Expand Down Expand Up @@ -144,5 +144,12 @@ pub enum Error {
Other(Box<dyn std::error::Error + Send + Sync>),
}

/// Convert [`PoisonError`] to [`Error`] for replace `unwrap` to `map_err`
impl<T: std::fmt::Debug> From<std::sync::PoisonError<T>> for Error {
fn from(e: std::sync::PoisonError<T>) -> Self {
Self::Other(format!("{:?}", e).into())
}
}

/// Convenience type for a result using the btleplug [`Error`] type.
pub type Result<T> = result::Result<T, Error>;
19 changes: 11 additions & 8 deletions src/winrtble/adapter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ fn get_central_state(radio: &Radio) -> CentralState {
}

impl Adapter {
pub(crate) fn new(radio: Radio) -> Self {
let watcher = Arc::new(Mutex::new(BLEWatcher::new()));
pub(crate) fn new(radio: Radio) -> Result<Self> {
let watcher = Arc::new(Mutex::new(BLEWatcher::new()?));
let manager = Arc::new(AdapterManager::default());

let radio_clone = radio.clone();
Expand All @@ -62,11 +62,11 @@ impl Adapter {
eprintln!("radio.StateChanged error: {}", err);
}

Adapter {
Ok(Adapter {
watcher,
manager,
radio,
}
})
}
}

Expand All @@ -87,12 +87,13 @@ impl Central for Adapter {
}

async fn start_scan(&self, filter: ScanFilter) -> Result<()> {
let watcher = self.watcher.lock().unwrap();
let watcher = self.watcher.lock()
.map_err(Into::<Error>::into)?;
let manager = self.manager.clone();
watcher.start(
filter,
Box::new(move |args| {
let bluetooth_address = args.BluetoothAddress().unwrap();
let bluetooth_address = args.BluetoothAddress()?;
let address: BDAddr = bluetooth_address.try_into().unwrap();
if let Some(mut entry) = manager.peripheral_mut(&address.into()) {
entry.value_mut().update_properties(args);
Expand All @@ -103,13 +104,15 @@ impl Central for Adapter {
manager.add_peripheral(peripheral);
manager.emit(CentralEvent::DeviceDiscovered(address.into()));
}
Ok(())
}),
)
}

async fn stop_scan(&self) -> Result<()> {
let watcher = self.watcher.lock().unwrap();
watcher.stop().unwrap();
let watcher = self.watcher.lock()
.map_err(Into::<Error>::into)?;
watcher.stop()?;
Ok(())
}

Expand Down
17 changes: 9 additions & 8 deletions src/winrtble/ble/characteristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ use windows::{
GattCommunicationStatus, GattValueChangedEventArgs, GattWriteOption,
},
},
Foundation::{EventRegistrationToken, TypedEventHandler},
Foundation::TypedEventHandler,
Storage::Streams::{DataReader, DataWriter},
};
use windows::core::Ref;

pub type NotifiyEventHandler = Box<dyn Fn(Vec<u8>) + Send>;

Expand All @@ -48,7 +49,7 @@ impl From<WriteType> for GattWriteOption {
pub struct BLECharacteristic {
characteristic: GattCharacteristic,
pub descriptors: HashMap<Uuid, BLEDescriptor>,
notify_token: Option<EventRegistrationToken>,
notify_token: Option<i64>,
}

impl BLECharacteristic {
Expand All @@ -69,7 +70,7 @@ impl BLECharacteristic {
let operation = self
.characteristic
.WriteValueWithOptionAsync(&writer.DetachBuffer()?, write_type.into())?;
let result = operation.await?;
let result = operation.get()?;
if result == GattCommunicationStatus::Success {
Ok(())
} else {
Expand All @@ -83,7 +84,7 @@ impl BLECharacteristic {
let result = self
.characteristic
.ReadValueWithCacheModeAsync(BluetoothCacheMode::Uncached)?
.await?;
.get()?;
if result.Status()? == GattCommunicationStatus::Success {
let value = result.Value()?;
let reader = DataReader::FromBuffer(&value)?;
Expand All @@ -101,8 +102,8 @@ impl BLECharacteristic {
pub async fn subscribe(&mut self, on_value_changed: NotifiyEventHandler) -> Result<()> {
{
let value_handler = TypedEventHandler::new(
move |_: &Option<GattCharacteristic>, args: &Option<GattValueChangedEventArgs>| {
if let Some(args) = args {
move |_: Ref<GattCharacteristic>, args: Ref<GattValueChangedEventArgs>| {
if let Ok(args) = args.ok() {
let value = args.CharacteristicValue()?;
let reader = DataReader::FromBuffer(&value)?;
let len = reader.UnconsumedBufferLength()? as usize;
Expand All @@ -125,7 +126,7 @@ impl BLECharacteristic {
let status = self
.characteristic
.WriteClientCharacteristicConfigurationDescriptorAsync(config)?
.await?;
.get()?;
trace!("subscribe {:?}", status);
if status == GattCommunicationStatus::Success {
Ok(())
Expand All @@ -145,7 +146,7 @@ impl BLECharacteristic {
let status = self
.characteristic
.WriteClientCharacteristicConfigurationDescriptorAsync(config)?
.await?;
.get()?;
trace!("unsubscribe {:?}", status);
if status == GattCommunicationStatus::Success {
Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/winrtble/ble/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl BLEDescriptor {
let writer = DataWriter::new()?;
writer.WriteBytes(data)?;
let operation = self.descriptor.WriteValueAsync(&writer.DetachBuffer()?)?;
let result = operation.await?;
let result = operation.get()?;
if result == GattCommunicationStatus::Success {
Ok(())
} else {
Expand All @@ -64,7 +64,7 @@ impl BLEDescriptor {
let result = self
.descriptor
.ReadValueWithCacheModeAsync(BluetoothCacheMode::Uncached)?
.await?;
.get()?;
if result.Status()? == GattCommunicationStatus::Success {
let value = result.Value()?;
let reader = DataReader::FromBuffer(&value)?;
Expand Down
Loading