use super::{
central_delegate::{CentralDelegate, CentralDelegateEvent},
framework::{
cb::{self, CBManagerAuthorization, CBPeripheralState},
ns,
},
future::{BtlePlugFuture, BtlePlugFutureStateShared},
utils::{
core_bluetooth::{cbuuid_to_uuid, uuid_to_cbuuid},
nsstring::nsstring_to_string,
nsuuid_to_uuid,
},
};
use crate::api::{CharPropFlags, Characteristic, ScanFilter, Service, WriteType};
use crate::Error;
use cocoa::{
base::{id, nil},
foundation::NSArray,
};
use futures::channel::mpsc::{self, Receiver, Sender};
use futures::select;
use futures::sink::SinkExt;
use futures::stream::{Fuse, StreamExt};
use log::{error, trace, warn};
use objc::{rc::StrongPtr, runtime::YES};
use std::{
collections::{BTreeSet, HashMap, VecDeque},
fmt::{self, Debug, Formatter},
ops::Deref,
thread,
};
use tokio::runtime;
use uuid::Uuid;
struct CBCharacteristic {
pub characteristic: StrongPtr,
pub uuid: Uuid,
pub properties: CharPropFlags,
pub read_future_state: VecDeque<CoreBluetoothReplyStateShared>,
pub write_future_state: VecDeque<CoreBluetoothReplyStateShared>,
pub subscribe_future_state: VecDeque<CoreBluetoothReplyStateShared>,
pub unsubscribe_future_state: VecDeque<CoreBluetoothReplyStateShared>,
}
impl Debug for CBCharacteristic {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("CBCharacteristic")
.field("characteristic", self.characteristic.deref())
.field("uuid", &self.uuid)
.field("properties", &self.properties)
.field("read_future_state", &self.read_future_state)
.field("write_future_state", &self.write_future_state)
.field("subscribe_future_state", &self.subscribe_future_state)
.field("unsubscribe_future_state", &self.unsubscribe_future_state)
.finish()
}
}
impl CBCharacteristic {
pub fn new(characteristic: StrongPtr) -> Self {
let properties = CBCharacteristic::form_flags(*characteristic);
let uuid = cbuuid_to_uuid(cb::attribute_uuid(*characteristic));
Self {
characteristic,
uuid,
properties,
read_future_state: VecDeque::with_capacity(10),
write_future_state: VecDeque::with_capacity(10),
subscribe_future_state: VecDeque::with_capacity(10),
unsubscribe_future_state: VecDeque::with_capacity(10),
}
}
fn form_flags(characteristic: id) -> CharPropFlags {
let flags = cb::characteristic_properties(characteristic);
let mut v = CharPropFlags::default();
if (flags & cb::CHARACTERISTICPROPERTY_BROADCAST) != 0 {
v |= CharPropFlags::BROADCAST;
}
if (flags & cb::CHARACTERISTICPROPERTY_READ) != 0 {
v |= CharPropFlags::READ;
}
if (flags & cb::CHARACTERISTICPROPERTY_WRITEWITHOUTRESPONSE) != 0 {
v |= CharPropFlags::WRITE_WITHOUT_RESPONSE;
}
if (flags & cb::CHARACTERISTICPROPERTY_WRITE) != 0 {
v |= CharPropFlags::WRITE;
}
if (flags & cb::CHARACTERISTICPROPERTY_NOTIFY) != 0 {
v |= CharPropFlags::NOTIFY;
}
if (flags & cb::CHARACTERISTICPROPERTY_INDICATE) != 0 {
v |= CharPropFlags::INDICATE;
}
if (flags & cb::CHARACTERISTICPROPERTY_AUTHENTICATEDSIGNEDWRITES) != 0 {
v |= CharPropFlags::AUTHENTICATED_SIGNED_WRITES;
}
trace!("Flags: {:?}", v);
v
}
}
#[derive(Clone, Debug)]
pub enum CoreBluetoothReply {
ReadResult(Vec<u8>),
Connected(BTreeSet<Service>),
State(CBPeripheralState),
Ok,
Err(String),
}
#[derive(Debug)]
pub enum CBPeripheralEvent {
Disconnected,
Notification(Uuid, Vec<u8>),
ManufacturerData(u16, Vec<u8>),
ServiceData(HashMap<Uuid, Vec<u8>>),
Services(Vec<Uuid>),
}
pub type CoreBluetoothReplyStateShared = BtlePlugFutureStateShared<CoreBluetoothReply>;
pub type CoreBluetoothReplyFuture = BtlePlugFuture<CoreBluetoothReply>;
struct ServiceInternal {
cbservice: StrongPtr,
characteristics: HashMap<Uuid, CBCharacteristic>,
}
struct CBPeripheral {
pub peripheral: StrongPtr,
services: HashMap<Uuid, ServiceInternal>,
pub event_sender: Sender<CBPeripheralEvent>,
pub connected_future_state: Option<CoreBluetoothReplyStateShared>,
}
impl Debug for CBPeripheral {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("CBPeripheral")
.field("peripheral", self.peripheral.deref())
.field(
"services",
&self
.services
.iter()
.map(|(service_uuid, service)| (service_uuid, service.characteristics.len()))
.collect::<HashMap<_, _>>(),
)
.field("event_sender", &self.event_sender)
.field("connected_future_state", &self.connected_future_state)
.finish()
}
}
impl CBPeripheral {
pub fn new(peripheral: StrongPtr, event_sender: Sender<CBPeripheralEvent>) -> Self {
Self {
peripheral,
services: HashMap::new(),
event_sender,
connected_future_state: None,
}
}
pub fn set_characteristics(
&mut self,
service_uuid: Uuid,
characteristics: HashMap<Uuid, StrongPtr>,
) {
let characteristics = characteristics
.into_iter()
.map(|(characteristic_uuid, characteristic)| {
(characteristic_uuid, CBCharacteristic::new(characteristic))
})
.collect();
let service = self
.services
.get_mut(&service_uuid)
.expect("Got characteristics for a service we don't know about");
service.characteristics = characteristics;
if !self
.services
.values()
.any(|service| service.characteristics.is_empty())
{
if self.connected_future_state.is_none() {
panic!("We should still have a future at this point!");
}
let services = self
.services
.iter()
.map(|(&service_uuid, service)| Service {
uuid: service_uuid,
primary: cb::service_isprimary(*service.cbservice) != objc::runtime::NO,
characteristics: service
.characteristics
.iter()
.map(|(&characteristic_uuid, characteristic)| Characteristic {
uuid: characteristic_uuid,
service_uuid,
properties: characteristic.properties,
})
.collect(),
})
.collect();
self.connected_future_state
.take()
.unwrap()
.lock()
.unwrap()
.set_reply(CoreBluetoothReply::Connected(services));
}
}
}
struct CoreBluetoothInternal {
manager: StrongPtr,
delegate: StrongPtr,
peripherals: HashMap<Uuid, CBPeripheral>,
delegate_receiver: Fuse<Receiver<CentralDelegateEvent>>,
event_sender: Sender<CoreBluetoothEvent>,
message_receiver: Fuse<Receiver<CoreBluetoothMessage>>,
}
impl Debug for CoreBluetoothInternal {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.debug_struct("CoreBluetoothInternal")
.field("manager", self.manager.deref())
.field("delegate", self.delegate.deref())
.field("peripherals", &self.peripherals)
.field("delegate_receiver", &self.delegate_receiver)
.field("event_sender", &self.event_sender)
.field("message_receiver", &self.message_receiver)
.finish()
}
}
#[derive(Debug)]
pub enum CoreBluetoothMessage {
StartScanning {
filter: ScanFilter,
},
StopScanning,
ConnectDevice {
peripheral_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
DisconnectDevice {
peripheral_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
ReadValue {
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
WriteValue {
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
data: Vec<u8>,
write_type: WriteType,
future: CoreBluetoothReplyStateShared,
},
Subscribe {
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
Unsubscribe {
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
IsConnected {
peripheral_uuid: Uuid,
future: CoreBluetoothReplyStateShared,
},
}
#[derive(Debug)]
pub enum CoreBluetoothEvent {
AdapterConnected,
DeviceDiscovered {
uuid: Uuid,
name: Option<String>,
event_receiver: Receiver<CBPeripheralEvent>,
},
DeviceUpdated {
uuid: Uuid,
name: String,
},
DeviceDisconnected {
uuid: Uuid,
},
}
impl CoreBluetoothInternal {
pub fn new(
message_receiver: Receiver<CoreBluetoothMessage>,
event_sender: Sender<CoreBluetoothEvent>,
) -> Self {
unsafe {
let (delegate, delegate_receiver) = CentralDelegate::delegate();
let delegate = StrongPtr::new(delegate);
Self {
manager: StrongPtr::new(cb::centralmanager(*delegate)),
peripherals: HashMap::new(),
delegate_receiver: delegate_receiver.fuse(),
event_sender,
message_receiver: message_receiver.fuse(),
delegate,
}
}
}
async fn dispatch_event(&self, event: CoreBluetoothEvent) {
let mut s = self.event_sender.clone();
if let Err(e) = s.send(event).await {
error!("Error dispatching event: {:?}", e);
}
}
async fn on_manufacturer_data(
&mut self,
peripheral_uuid: Uuid,
manufacturer_id: u16,
manufacturer_data: Vec<u8>,
) {
trace!(
"Got manufacturer data advertisement! {}: {:?}",
manufacturer_id,
manufacturer_data
);
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
if let Err(e) = p
.event_sender
.send(CBPeripheralEvent::ManufacturerData(
manufacturer_id,
manufacturer_data,
))
.await
{
error!("Error sending notification event: {}", e);
}
}
}
async fn on_service_data(
&mut self,
peripheral_uuid: Uuid,
service_data: HashMap<Uuid, Vec<u8>>,
) {
trace!("Got service data advertisement! {:?}", service_data);
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
if let Err(e) = p
.event_sender
.send(CBPeripheralEvent::ServiceData(service_data))
.await
{
error!("Error sending notification event: {}", e);
}
}
}
async fn on_services(&mut self, peripheral_uuid: Uuid, services: Vec<Uuid>) {
trace!("Got service advertisement! {:?}", services);
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
if let Err(e) = p
.event_sender
.send(CBPeripheralEvent::Services(services))
.await
{
error!("Error sending notification event: {}", e);
}
}
}
async fn on_discovered_peripheral(&mut self, peripheral: StrongPtr) {
let uuid = nsuuid_to_uuid(cb::peer_identifier(*peripheral));
let name = nsstring_to_string(cb::peripheral_name(*peripheral));
if self.peripherals.contains_key(&uuid) {
if let Some(name) = name {
self.dispatch_event(CoreBluetoothEvent::DeviceUpdated { uuid, name })
.await;
}
} else {
let (event_sender, event_receiver) = mpsc::channel(256);
self.peripherals
.insert(uuid, CBPeripheral::new(peripheral, event_sender));
self.dispatch_event(CoreBluetoothEvent::DeviceDiscovered {
uuid,
name,
event_receiver,
})
.await;
}
}
fn on_discovered_services(
&mut self,
peripheral_uuid: Uuid,
service_map: HashMap<Uuid, StrongPtr>,
) {
trace!("Found services!");
for id in service_map.keys() {
trace!("{}", id);
}
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
let services = service_map
.into_iter()
.map(|(service_uuid, cbservice)| {
(
service_uuid,
ServiceInternal {
cbservice,
characteristics: HashMap::new(),
},
)
})
.collect();
p.services = services;
}
}
fn on_discovered_characteristics(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristics: HashMap<Uuid, StrongPtr>,
) {
trace!(
"Found characteristics for peripheral {} service {}:",
peripheral_uuid,
service_uuid
);
for id in characteristics.keys() {
trace!("{}", id);
}
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
p.set_characteristics(service_uuid, characteristics);
}
}
fn on_peripheral_connect(&mut self, _peripheral_uuid: Uuid) {
}
async fn on_peripheral_disconnect(&mut self, uuid: Uuid) {
trace!("Got disconnect event!");
self.peripherals.remove(&uuid);
self.dispatch_event(CoreBluetoothEvent::DeviceDisconnected { uuid })
.await;
}
fn get_characteristic(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
) -> Option<&mut CBCharacteristic> {
self.peripherals
.get_mut(&peripheral_uuid)?
.services
.get_mut(&service_uuid)?
.characteristics
.get_mut(&characteristic_uuid)
}
fn on_characteristic_subscribed(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
) {
if let Some(characteristic) =
self.get_characteristic(peripheral_uuid, service_uuid, characteristic_uuid)
{
trace!("Got subscribed event!");
let state = characteristic.subscribe_future_state.pop_back().unwrap();
state.lock().unwrap().set_reply(CoreBluetoothReply::Ok);
}
}
fn on_characteristic_unsubscribed(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
) {
if let Some(characteristic) =
self.get_characteristic(peripheral_uuid, service_uuid, characteristic_uuid)
{
trace!("Got unsubscribed event!");
let state = characteristic.unsubscribe_future_state.pop_back().unwrap();
state.lock().unwrap().set_reply(CoreBluetoothReply::Ok);
}
}
async fn on_characteristic_read(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
data: Vec<u8>,
) {
if let Some(peripheral) = self.peripherals.get_mut(&peripheral_uuid) {
if let Some(service) = peripheral.services.get_mut(&service_uuid) {
if let Some(characteristic) = service.characteristics.get_mut(&characteristic_uuid)
{
trace!("Got read event!");
let mut data_clone = Vec::new();
for byte in data.iter() {
data_clone.push(*byte);
}
if !characteristic.read_future_state.is_empty() {
let state = characteristic.read_future_state.pop_back().unwrap();
state
.lock()
.unwrap()
.set_reply(CoreBluetoothReply::ReadResult(data_clone));
} else if let Err(e) = peripheral
.event_sender
.send(CBPeripheralEvent::Notification(characteristic_uuid, data))
.await
{
error!("Error sending notification event: {}", e);
}
}
}
}
}
fn on_characteristic_written(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
) {
if let Some(characteristic) =
self.get_characteristic(peripheral_uuid, service_uuid, characteristic_uuid)
{
trace!("Got written event!");
let state = characteristic.write_future_state.pop_back().unwrap();
state.lock().unwrap().set_reply(CoreBluetoothReply::Ok);
}
}
fn connect_peripheral(&mut self, peripheral_uuid: Uuid, fut: CoreBluetoothReplyStateShared) {
trace!("Trying to connect peripheral!");
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
trace!("Connecting peripheral!");
p.connected_future_state = Some(fut);
cb::centralmanager_connectperipheral(*self.manager, *p.peripheral);
}
}
fn is_connected(&mut self, peripheral_uuid: Uuid, fut: CoreBluetoothReplyStateShared) {
if let Some(p) = self.peripherals.get_mut(&peripheral_uuid) {
let state = cb::peripheral_state(*p.peripheral);
trace!("Connected state {:?} ", state);
fut.lock()
.unwrap()
.set_reply(CoreBluetoothReply::State(state));
}
}
fn write_value(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
data: Vec<u8>,
kind: WriteType,
fut: CoreBluetoothReplyStateShared,
) {
if let Some(peripheral) = self.peripherals.get_mut(&peripheral_uuid) {
if let Some(service) = peripheral.services.get_mut(&service_uuid) {
if let Some(characteristic) = service.characteristics.get_mut(&characteristic_uuid)
{
trace!("Writing value! With kind {:?}", kind);
cb::peripheral_writevalue_forcharacteristic(
*peripheral.peripheral,
ns::data(&data),
*characteristic.characteristic,
match kind {
WriteType::WithResponse => 0,
WriteType::WithoutResponse => 1,
},
);
if kind == WriteType::WithoutResponse {
fut.lock().unwrap().set_reply(CoreBluetoothReply::Ok);
} else {
characteristic.write_future_state.push_front(fut);
}
}
}
}
}
fn read_value(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
fut: CoreBluetoothReplyStateShared,
) {
if let Some(peripheral) = self.peripherals.get_mut(&peripheral_uuid) {
if let Some(service) = peripheral.services.get_mut(&service_uuid) {
if let Some(characteristic) = service.characteristics.get_mut(&characteristic_uuid)
{
trace!("Reading value!");
cb::peripheral_readvalue_forcharacteristic(
*peripheral.peripheral,
*characteristic.characteristic,
);
characteristic.read_future_state.push_front(fut);
}
}
}
}
fn subscribe(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
fut: CoreBluetoothReplyStateShared,
) {
if let Some(peripheral) = self.peripherals.get_mut(&peripheral_uuid) {
if let Some(service) = peripheral.services.get_mut(&service_uuid) {
if let Some(characteristic) = service.characteristics.get_mut(&characteristic_uuid)
{
trace!("Setting subscribe!");
cb::peripheral_setnotifyvalue_forcharacteristic(
*peripheral.peripheral,
objc::runtime::YES,
*characteristic.characteristic,
);
characteristic.subscribe_future_state.push_front(fut);
}
}
}
}
fn unsubscribe(
&mut self,
peripheral_uuid: Uuid,
service_uuid: Uuid,
characteristic_uuid: Uuid,
fut: CoreBluetoothReplyStateShared,
) {
if let Some(peripheral) = self.peripherals.get_mut(&peripheral_uuid) {
if let Some(service) = peripheral.services.get_mut(&service_uuid) {
if let Some(characteristic) = service.characteristics.get_mut(&characteristic_uuid)
{
trace!("Setting subscribe!");
cb::peripheral_setnotifyvalue_forcharacteristic(
*peripheral.peripheral,
objc::runtime::NO,
*characteristic.characteristic,
);
characteristic.unsubscribe_future_state.push_front(fut);
}
}
}
}
async fn wait_for_message(&mut self) {
select! {
delegate_msg = self.delegate_receiver.select_next_some() => {
match delegate_msg {
CentralDelegateEvent::DidUpdateState => {
self.dispatch_event(CoreBluetoothEvent::AdapterConnected).await
}
CentralDelegateEvent::DiscoveredPeripheral{cbperipheral} => {
self.on_discovered_peripheral(cbperipheral).await
}
CentralDelegateEvent::DiscoveredServices{peripheral_uuid, services} => {
self.on_discovered_services(peripheral_uuid, services)
}
CentralDelegateEvent::DiscoveredCharacteristics{peripheral_uuid, service_uuid, characteristics} => {
self.on_discovered_characteristics(peripheral_uuid, service_uuid, characteristics)
}
CentralDelegateEvent::ConnectedDevice{peripheral_uuid} => {
self.on_peripheral_connect(peripheral_uuid)
}
CentralDelegateEvent::DisconnectedDevice{peripheral_uuid} => {
self.on_peripheral_disconnect(peripheral_uuid).await
}
CentralDelegateEvent::CharacteristicSubscribed{
peripheral_uuid,
service_uuid,
characteristic_uuid,
} => self.on_characteristic_subscribed(peripheral_uuid, service_uuid, characteristic_uuid),
CentralDelegateEvent::CharacteristicUnsubscribed{
peripheral_uuid,
service_uuid,
characteristic_uuid,
} => self.on_characteristic_unsubscribed(peripheral_uuid, service_uuid,characteristic_uuid),
CentralDelegateEvent::CharacteristicNotified{
peripheral_uuid,
service_uuid,
characteristic_uuid,
data,
} => self.on_characteristic_read(peripheral_uuid, service_uuid,characteristic_uuid, data).await,
CentralDelegateEvent::CharacteristicWritten{
peripheral_uuid,
service_uuid,
characteristic_uuid,
} => self.on_characteristic_written(peripheral_uuid, service_uuid, characteristic_uuid),
CentralDelegateEvent::ManufacturerData{peripheral_uuid, manufacturer_id, data} => {
self.on_manufacturer_data(peripheral_uuid, manufacturer_id, data).await
},
CentralDelegateEvent::ServiceData{peripheral_uuid, service_data} => {
self.on_service_data(peripheral_uuid, service_data).await
},
CentralDelegateEvent::Services{peripheral_uuid, service_uuids} => {
self.on_services(peripheral_uuid, service_uuids).await
},
};
}
adapter_msg = self.message_receiver.select_next_some() => {
trace!("Adapter message!");
match adapter_msg {
CoreBluetoothMessage::StartScanning{filter} => self.start_discovery(filter),
CoreBluetoothMessage::StopScanning => self.stop_discovery(),
CoreBluetoothMessage::ConnectDevice{peripheral_uuid, future} => {
trace!("got connectdevice msg!");
self.connect_peripheral(peripheral_uuid, future);
}
CoreBluetoothMessage::DisconnectDevice{peripheral_uuid:_, future:_} => {}
CoreBluetoothMessage::ReadValue{peripheral_uuid, service_uuid,characteristic_uuid, future} => {
self.read_value(peripheral_uuid, service_uuid,characteristic_uuid, future)
}
CoreBluetoothMessage::WriteValue{
peripheral_uuid,service_uuid,
characteristic_uuid,
data,
write_type,
future,
} => self.write_value(peripheral_uuid, service_uuid,characteristic_uuid, data, write_type, future),
CoreBluetoothMessage::Subscribe{peripheral_uuid, service_uuid,characteristic_uuid, future} => {
self.subscribe(peripheral_uuid, service_uuid,characteristic_uuid, future)
}
CoreBluetoothMessage::Unsubscribe{peripheral_uuid, service_uuid,characteristic_uuid, future} => {
self.unsubscribe(peripheral_uuid, service_uuid,characteristic_uuid, future)
}
CoreBluetoothMessage::IsConnected{peripheral_uuid, future} => {
self.is_connected(peripheral_uuid, future);
}
};
}
}
}
fn start_discovery(&mut self, filter: ScanFilter) {
trace!("BluetoothAdapter::start_discovery");
let service_uuids = scan_filter_to_service_uuids(filter);
let options = ns::mutabledictionary();
ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(YES), unsafe {
cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY
});
cb::centralmanager_scanforperipheralswithservices_options(
*self.manager,
service_uuids,
options,
);
}
fn stop_discovery(&mut self) {
trace!("BluetoothAdapter::stop_discovery");
cb::centralmanager_stopscan(*self.manager);
}
}
fn scan_filter_to_service_uuids(filter: ScanFilter) -> id {
if filter.services.is_empty() {
nil
} else {
let service_uuids = filter
.services
.into_iter()
.map(uuid_to_cbuuid)
.collect::<Vec<_>>();
unsafe { NSArray::arrayWithObjects(nil, &service_uuids) }
}
}
impl Drop for CoreBluetoothInternal {
fn drop(&mut self) {
trace!("BluetoothAdapter::drop");
self.stop_discovery();
CentralDelegate::delegate_drop_channel(*self.delegate);
}
}
pub fn run_corebluetooth_thread(
event_sender: Sender<CoreBluetoothEvent>,
) -> Result<Sender<CoreBluetoothMessage>, Error> {
let authorization = cb::manager_authorization();
if authorization != CBManagerAuthorization::AllowedAlways
&& authorization != CBManagerAuthorization::NotDetermined
{
warn!("Authorization status {:?}", authorization);
return Err(Error::PermissionDenied);
} else {
trace!("Authorization status {:?}", authorization);
}
let (sender, receiver) = mpsc::channel::<CoreBluetoothMessage>(256);
thread::spawn(move || {
let runtime = runtime::Builder::new_current_thread().build().unwrap();
runtime.block_on(async move {
let mut cbi = CoreBluetoothInternal::new(receiver, event_sender);
loop {
cbi.wait_for_message().await;
}
})
});
Ok(sender)
}