diff --git a/Cargo.toml b/Cargo.toml index ed77ba06..964d10e6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ objc2-foundation = { version = "0.2.2", default-features = false, features = [ "NSString", "NSUUID", "NSValue", + "NSProcessInfo", ] } objc2-core-bluetooth = { version = "0.2.2", default-features = false, features = [ "std", diff --git a/src/corebluetooth/internal.rs b/src/corebluetooth/internal.rs index 93597bc7..2af0f201 100644 --- a/src/corebluetooth/internal.rs +++ b/src/corebluetooth/internal.rs @@ -31,13 +31,14 @@ use objc2_core_bluetooth::{ CBCharacteristicProperties, CBCharacteristicWriteType, CBDescriptor, CBManager, CBManagerAuthorization, CBManagerState, CBPeripheral, CBPeripheralState, CBService, CBUUID, }; -use objc2_foundation::{NSArray, NSData, NSMutableDictionary, NSNumber}; +use objc2_foundation::{NSArray, NSData, NSMutableDictionary, NSNumber, NSProcessInfo}; use std::{ collections::{BTreeSet, HashMap, VecDeque}, ffi::CString, fmt::{self, Debug, Formatter}, ops::Deref, thread, + time::Duration, }; use tokio::runtime; use uuid::Uuid; @@ -368,6 +369,7 @@ impl PeripheralInternal { struct CoreBluetoothInternal { manager: Retained, delegate: Retained, + can_send_without_response_supported: bool, // Map of identifiers to object pointers peripherals: HashMap, delegate_receiver: Fuse>, @@ -491,8 +493,16 @@ impl CoreBluetoothInternal { msg_send_id![CBCentralManager::alloc(), initWithDelegate: &*delegate, queue: queue] }; + let process_info = unsafe { NSProcessInfo::processInfo() }; + let version = unsafe { process_info.operatingSystemVersion() }; + let mut can_send_without_response_supported = false; + if (version.majorVersion, version.minorVersion) >= (11, 2) { + can_send_without_response_supported = true; + } + Self { manager, + can_send_without_response_supported, peripherals: HashMap::new(), delegate_receiver: receiver.fuse(), event_sender, @@ -887,6 +897,21 @@ impl CoreBluetoothInternal { { trace!("Writing value! With kind {:?}", kind); unsafe { + if kind == WriteType::WithoutResponse + && self.can_send_without_response_supported + { + // probably better idea would be to wait for the result of peripheral.peripheralIsReadyToSendWriteWithoutResponse + let mut attempts = 0; + while !peripheral.peripheral.canSendWriteWithoutResponse() + && attempts < 100 + { + attempts += 1; + // min. connection interval time is 15ms. see the document: + // https://developer.apple.com/library/archive/qa/qa1931/_index.html + thread::sleep(Duration::from_millis(15)); + } + } + peripheral.peripheral.writeValue_forCharacteristic_type( &NSData::from_vec(data), &characteristic.characteristic,