diff --git a/CHANGELOG.md b/CHANGELOG.md index 49e13439..16b598eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# 0.11.4 (2024-01-01) + +## Bugfixes + +- Fix issue with manufacturer data not being consistently found on windows +- Fix UUID used for finding characteristics on windows +- Peripheral connection failure now returns an error +- Peripheral service discovery failure now returns an error + # 0.11.3 (2023-11-18) ## Bugfixes diff --git a/Cargo.toml b/Cargo.toml index acca3d75..6b788a53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "btleplug" -version = "0.11.3" +version = "0.11.4" authors = ["Nonpolynomial, LLC "] license = "MIT/Apache-2.0/BSD-3-Clause" repository = "https://github.com/deviceplug/btleplug" @@ -22,18 +22,18 @@ path = "src/lib.rs" serde = ["uuid/serde", "serde_cr", "serde_bytes"] [dependencies] -async-trait = "0.1.74" +async-trait = "0.1.76" log = "0.4.20" bitflags = "2.4.1" -thiserror = "1.0.50" -uuid = "1.5.0" -serde_cr = { package = "serde", version = "1.0.192", features = ["derive"], default-features = false, optional = true } -serde_bytes = { version = "0.11.12", optional = true } +thiserror = "1.0.53" +uuid = "1.6.1" +serde_cr = { package = "serde", version = "1.0.193", features = ["derive"], default-features = false, optional = true } +serde_bytes = { version = "0.11.13", optional = true } dashmap = "5.5.3" -futures = "0.3.29" +futures = "0.3.30" static_assertions = "1.1.0" # rt feature needed for block_on in macOS internal thread -tokio = { version = "1.34.0", features = ["sync", "rt"] } +tokio = { version = "1.35.1", features = ["sync", "rt"] } tokio-stream = { version = "0.1.14", features = ["sync"] } [target.'cfg(target_os = "linux")'.dependencies] @@ -42,13 +42,13 @@ bluez-async = "0.7.2" [target.'cfg(target_os = "android")'.dependencies] jni = "0.19.0" -once_cell = "1.18.0" +once_cell = "1.19.0" jni-utils = "0.1.1" [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies] cocoa = "0.25.0" objc = "0.2.7" -libc = "0.2.150" +libc = "0.2.151" [target.'cfg(target_os = "windows")'.dependencies] windows = { version = "0.52.0", features = ["Devices_Bluetooth", "Devices_Bluetooth_GenericAttributeProfile", "Devices_Bluetooth_Advertisement", "Devices_Radios", "Foundation_Collections", "Foundation", "Storage_Streams"] } @@ -56,5 +56,5 @@ windows = { version = "0.52.0", features = ["Devices_Bluetooth", "Devices_Blueto [dev-dependencies] rand = "0.8.5" pretty_env_logger = "0.5.0" -tokio = { version = "1.34.0", features = ["macros", "rt", "rt-multi-thread"] } -serde_json = "1.0.108" +tokio = { version = "1.35.1", features = ["macros", "rt", "rt-multi-thread"] } +serde_json = "1.0.109" diff --git a/src/corebluetooth/central_delegate.rs b/src/corebluetooth/central_delegate.rs index 6cba34b5..bf3dfe67 100644 --- a/src/corebluetooth/central_delegate.rs +++ b/src/corebluetooth/central_delegate.rs @@ -91,6 +91,7 @@ pub enum CentralDelegateEvent { }, ConnectionFailed { peripheral_uuid: Uuid, + error_description: Option, }, DisconnectedDevice { peripheral_uuid: Uuid, @@ -176,9 +177,13 @@ impl Debug for CentralDelegateEvent { .debug_struct("ConnectedDevice") .field("peripheral_uuid", peripheral_uuid) .finish(), - CentralDelegateEvent::ConnectionFailed { peripheral_uuid } => f + CentralDelegateEvent::ConnectionFailed { + peripheral_uuid, + error_description, + } => f .debug_struct("ConnectionFailed") .field("peripheral_uuid", peripheral_uuid) + .field("error_description", error_description) .finish(), CentralDelegateEvent::DisconnectedDevice { peripheral_uuid } => f .debug_struct("DisconnectedDevice") @@ -486,13 +491,18 @@ pub mod CentralDelegate { _cmd: Sel, _central: id, peripheral: id, - _error: id, + error: id, ) { trace!("delegate_centralmanager_didfailtoconnectperipheral_error"); let peripheral_uuid = nsuuid_to_uuid(cb::peer_identifier(peripheral)); + let error_description_ns = ns::error_localizeddescription(error); + let error_description = nsstring_to_string(error_description_ns); send_delegate_event( delegate, - CentralDelegateEvent::ConnectionFailed { peripheral_uuid }, + CentralDelegateEvent::ConnectionFailed { + peripheral_uuid, + error_description, + }, ); } diff --git a/src/corebluetooth/framework.rs b/src/corebluetooth/framework.rs index b00830b2..2efa110b 100644 --- a/src/corebluetooth/framework.rs +++ b/src/corebluetooth/framework.rs @@ -94,6 +94,15 @@ pub mod ns { uuidstring } } + + // NSError + + pub fn error_localizeddescription(nserror: id) -> id /* NSString* */ { + unsafe { + let description: id = msg_send![nserror, localizedDescription]; + description + } + } } pub mod cb { diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index 8d538196..2aa00dc5 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -606,8 +606,13 @@ impl CoreBluetoothInternal { // itself when it receives all of its service/characteristic info. } - fn on_peripheral_connection_failed(&mut self, peripheral_uuid: Uuid) { + fn on_peripheral_connection_failed( + &mut self, + peripheral_uuid: Uuid, + error_description: Option, + ) { trace!("Got connection fail event!"); + let error = error_description.unwrap_or(String::from("Connection failed")); if self.peripherals.contains_key(&peripheral_uuid) { let peripheral = self .peripherals @@ -619,7 +624,7 @@ impl CoreBluetoothInternal { .unwrap() .lock() .unwrap() - .set_reply(CoreBluetoothReply::Err(String::from("Connection failed"))); + .set_reply(CoreBluetoothReply::Err(error)); } } @@ -1026,8 +1031,8 @@ impl CoreBluetoothInternal { CentralDelegateEvent::ConnectedDevice{peripheral_uuid} => { self.on_peripheral_connect(peripheral_uuid) }, - CentralDelegateEvent::ConnectionFailed{peripheral_uuid} => { - self.on_peripheral_connection_failed(peripheral_uuid) + CentralDelegateEvent::ConnectionFailed{peripheral_uuid, error_description} => { + self.on_peripheral_connection_failed(peripheral_uuid, error_description) }, CentralDelegateEvent::DisconnectedDevice{peripheral_uuid} => { self.on_peripheral_disconnect(peripheral_uuid).await diff --git a/src/corebluetooth/peripheral.rs b/src/corebluetooth/peripheral.rs index 5a8cf1bd..462ee55a 100644 --- a/src/corebluetooth/peripheral.rs +++ b/src/corebluetooth/peripheral.rs @@ -252,7 +252,8 @@ impl api::Peripheral for Peripheral { self.shared .emit_event(CentralEvent::DeviceConnected(self.shared.uuid.into())); } - _ => panic!("Shouldn't get anything but connected!"), + CoreBluetoothReply::Err(msg) => return Err(Error::RuntimeError(msg)), + _ => panic!("Shouldn't get anything but connected or err!"), } trace!("Device connected!"); Ok(()) diff --git a/src/winrtble/ble/watcher.rs b/src/winrtble/ble/watcher.rs index 29304d8c..fb9126a2 100644 --- a/src/winrtble/ble/watcher.rs +++ b/src/winrtble/ble/watcher.rs @@ -51,6 +51,7 @@ impl BLEWatcher { self.watcher .SetScanningMode(BluetoothLEScanningMode::Active) .unwrap(); + self.watcher.SetAllowExtendedAdvertisements(true)?; let handler: TypedEventHandler< BluetoothLEAdvertisementWatcher, BluetoothLEAdvertisementReceivedEventArgs, diff --git a/src/winrtble/peripheral.rs b/src/winrtble/peripheral.rs index c2ba385f..5dc97480 100644 --- a/src/winrtble/peripheral.rs +++ b/src/winrtble/peripheral.rs @@ -146,23 +146,25 @@ impl Peripheral { } } if let Ok(manufacturer_data) = advertisement.ManufacturerData() { - let mut manufacturer_data_guard = self.shared.latest_manufacturer_data.write().unwrap(); - - *manufacturer_data_guard = manufacturer_data - .into_iter() - .map(|d| { - let manufacturer_id = d.CompanyId().unwrap(); - let data = utils::to_vec(&d.Data().unwrap()); - - (manufacturer_id, data) - }) - .collect(); - - // Emit event of newly received advertisement - self.emit_event(CentralEvent::ManufacturerDataAdvertisement { - id: self.shared.address.into(), - manufacturer_data: manufacturer_data_guard.clone(), - }); + if manufacturer_data.Size().unwrap() > 0 { + let mut manufacturer_data_guard = + self.shared.latest_manufacturer_data.write().unwrap(); + *manufacturer_data_guard = manufacturer_data + .into_iter() + .map(|d| { + let manufacturer_id = d.CompanyId().unwrap(); + let data = utils::to_vec(&d.Data().unwrap()); + + (manufacturer_id, data) + }) + .collect(); + + // Emit event of newly received advertisement + self.emit_event(CentralEvent::ManufacturerDataAdvertisement { + id: self.shared.address.into(), + manufacturer_data: manufacturer_data_guard.clone(), + }); + } } // The Windows Runtime API (as of 19041) does not directly expose Service Data as a friendly API (like Manufacturer Data above) @@ -454,6 +456,7 @@ impl ApiPeripheral for Peripheral { } Err(e) => { error!("get_characteristics_async {:?}", e); + return Err(e); } } } @@ -572,7 +575,7 @@ impl ApiPeripheral for Peripheral { .ok_or_else(|| Error::NotSupported("Service not found for read".into()))?; let ble_characteristic = ble_service .characteristics - .get(&descriptor.uuid) + .get(&descriptor.characteristic_uuid) .ok_or_else(|| Error::NotSupported("Characteristic not found for read".into()))?; let ble_descriptor = ble_characteristic .descriptors