Skip to content

Commit

Permalink
Fix: CoreBluetooth sometimes returns incorrect data, always providing…
Browse files Browse the repository at this point in the history
… the latest data.
  • Loading branch information
soSeven committed Dec 27, 2024
1 parent 4a754ee commit fd6f6f0
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 7 deletions.
16 changes: 11 additions & 5 deletions src/corebluetooth/characteristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,15 @@ impl CharacteristicImpl {

loop {
match receiver.recv().await.map_err(Error::from_recv_error)? {
PeripheralEvent::CharacteristicValueUpdate { characteristic, error }
PeripheralEvent::CharacteristicValueUpdate { characteristic, data, error }
if characteristic == self.inner =>
{
match error {
Some(err) => return Err(Error::from_nserror(err)),
None => return self.value().await,
None => {
let data = data.map(|val| val.bytes().to_vec()).unwrap_or_default();
return Ok(data);
},
}
}
PeripheralEvent::Disconnected { error } => {
Expand Down Expand Up @@ -241,12 +244,15 @@ impl CharacteristicImpl {
.filter_map(move |x| {
let _guard = &guard;
match x {
PeripheralEvent::CharacteristicValueUpdate { characteristic, error }
PeripheralEvent::CharacteristicValueUpdate { characteristic, data, error }
if characteristic == self.inner =>
{
match error {
Some(err) => Some(Err(Error::from_nserror(err))),
None => Some(Ok(())),
None => {
let data = data.map(|val| val.bytes().to_vec()).unwrap_or_default();
Some(Ok(data))
},
}
}
PeripheralEvent::Disconnected { error } => {
Expand All @@ -263,7 +269,7 @@ impl CharacteristicImpl {
.then(move |x| {
Box::pin(async move {
match x {
Ok(_) => self.value().await,
Ok(data) => Ok(data),
Err(err) => Err(err),
}
})
Expand Down
29 changes: 27 additions & 2 deletions src/corebluetooth/delegates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ use std::os::raw::c_void;
use std::sync::Once;

use objc::declare::ClassDecl;
use objc::rc::autoreleasepool;
use objc::runtime::{Class, Object, Protocol, Sel};
use objc::{class, msg_send, sel, sel_impl};
use objc_foundation::{INSArray, NSArray, NSDictionary, NSObject, NSString};
use objc_foundation::{INSArray, NSArray, NSData, NSDictionary, NSObject, NSString};
use objc_id::{Id, ShareId, Shared};
use tracing::{debug, error};

use super::types::{id, CBCharacteristic, CBDescriptor, CBL2CAPChannel, CBPeripheral, CBService, NSError, NSInteger};
use crate::corebluetooth::types::option_from_ptr;
use crate::ConnectionEvent;

#[derive(Clone)]
Expand Down Expand Up @@ -88,6 +90,7 @@ pub enum PeripheralEvent {
},
CharacteristicValueUpdate {
characteristic: ShareId<CBCharacteristic>,
data: Option<ShareId<NSData>>,
error: Option<ShareId<NSError>>,
},
DescriptorValueUpdate {
Expand Down Expand Up @@ -525,11 +528,33 @@ impl PeripheralDelegate {
unsafe { *this.get_ivar("receiver") }
}

extern "C" fn did_update_value_for_characteristic(
this: &mut Object,
_sel: Sel,
_peripheral: *mut Object,
characteristic: *mut Object,
error: *mut Object,
) {
unsafe {
let ptr = (*this.get_ivar::<*mut c_void>("sender")).cast::<async_broadcast::Sender<PeripheralEvent>>();
if !ptr.is_null() {
let data: Option<ShareId<NSData>> =
autoreleasepool(move || option_from_ptr(msg_send![characteristic, value]));
let event = PeripheralEvent::CharacteristicValueUpdate {
characteristic: ShareId::from_ptr(characteristic.cast()),
data: data,
error: (!error.is_null()).then(|| ShareId::from_ptr(error.cast())),
};
debug!("PeripheralDelegate received {:?}", event);
let _res = (*ptr).try_broadcast(event);
}
}
}

delegate_method!(did_discover_services<DiscoveredServices>(peripheral, error: Option));
delegate_method!(did_discover_included_services<DiscoveredIncludedServices>(peripheral, service: Object, error: Option));
delegate_method!(did_discover_characteristics<DiscoveredCharacteristics>(peripheral, service: Object, error: Option));
delegate_method!(did_discover_descriptors<DiscoveredDescriptors>(peripheral, characteristic: Object, error: Option));
delegate_method!(did_update_value_for_characteristic<CharacteristicValueUpdate>(peripheral, characteristic: Object, error: Option));
delegate_method!(did_update_value_for_descriptor<DescriptorValueUpdate>(peripheral, descriptor: Object, error: Option));
delegate_method!(did_write_value_for_characteristic<CharacteristicValueWrite>(peripheral, characteristic: Object, error: Option));
delegate_method!(did_write_value_for_descriptor<DescriptorValueWrite>(peripheral, descriptor: Object, error: Option));
Expand Down

0 comments on commit fd6f6f0

Please sign in to comment.