1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! Safe wrapper around [Core Bluetooth framework](https://developer.apple.com/documentation/corebluetooth)
//! used to communicate with Bluetooth-equipped low energy (LE) and Basic Rate / Enhanced Data Rate
//! (BR/EDR) wireless technology.
//!
//! The API closely resembles to the native API with some changes for consistency sake.
//! The main difference is that this API lacks most of the functions for accessing retained
//! state, for thread-safety reasons. If needed users can maintain the retained state via
//! information from events.
//!
//! # Central role
//!
//! Central role is when application acts as "central" and initiates discovery of and connections
//! to peripherals. The [`central`](central/index.html) package contains all the needed objects for
//! central role.
//!
//! ## Example
//!
//! The following example shows how to discover peripherals, services and characteristics,
//! connect to peripherals and subscribe to characteristics.
//!
//! ```no_run
//! use core_bluetooth::*;
//! use core_bluetooth::central::*;
//!
//! let (central, receiver) = CentralManager::new();
//!
//! let handle_event = |event| {
//!     match event {
//!         CentralEvent::ManagerStateChanged { new_state } => {
//!             match new_state {
//!                 // Must be in PoweredOn state.
//!                 ManagerState::PoweredOn => central.scan(),
//!                 _ => panic!("no bluetooth available"),
//!             }
//!         }
//!         CentralEvent::PeripheralDiscovered { peripheral, advertisement_data, .. } => {
//!             if advertisement_data.is_connectable() != Some(false) {
//!                 central.connect(&peripheral);
//!             }
//!         }
//!         CentralEvent::PeripheralConnected { peripheral } => {
//!             peripheral.discover_services_with_uuids(&[
//!                 "ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6".parse().unwrap()]);
//!         }
//!         CentralEvent::ServicesDiscovered { peripheral, services } => {
//!             if let Ok(services) = services {
//!                 for service in services {
//!                     peripheral.discover_characteristics_with_uuids(&service, &[
//!                         "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6".parse().unwrap()]);
//!                 }
//!             }
//!         }
//!         CentralEvent::CharacteristicsDiscovered { peripheral, characteristics, .. } => {
//!             if let Ok(chars) = characteristics {
//!                 peripheral.subscribe(&chars[0]);
//!             }
//!         }
//!         CentralEvent::CharacteristicValue { peripheral, value, .. } => {
//!             if let Ok(value) = value {
//!                 // Decode the value.
//!                 // In this example the value comes from a Xiaomi temperature sensor.
//!                 let t = i16::from_le_bytes([value[0], value[1]]) as f64 / 100.0;
//!                 let rh = value[2];
//!                 println!("t = {} C, rh = {}%", t, rh);
//!             }
//!         }
//!         _ => {}
//!     }
//! };
#![cfg_attr(not(feature = "async_std_unstable"), doc =r#"
while let Ok(event) = receiver.recv() {
    handle_event(event);
}
"#)]
#![cfg_attr(feature = "async_std_unstable", doc =r#"
async_std::task::block_on(async move {
    while let Some(event) = receiver.recv().await {
        handle_event(event);
    }
})
"#)]
//! ```
//!
//! You can find more examples in the `examples` directory.
#![deny(dead_code)]
#![deny(non_snake_case)]
#![deny(unused_imports)]
#![deny(unused_must_use)]

#[macro_use]
mod macros;

pub mod central;
pub mod error;
mod platform;
mod sync;
pub mod uuid;
mod util;

use static_assertions::*;

pub use sync::Receiver;

/// Arbitrary data to associate with asynchronous API call.
pub type Tag = Box<dyn std::any::Any + Send>;

assert_impl_all!(Tag: Send);
assert_not_impl_any!(Tag: Sync);

/// The possible states of a Core Bluetooth manager.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[non_exhaustive]
pub enum ManagerState {
    /// The manager’s state is unknown.
    Unknown = 0,

    /// A state that indicates the connection with the system service was momentarily lost.
    Resetting = 1,

    /// A state that indicates this device doesn’t support the Bluetooth low energy central or client role.
    Unsupported = 2,

    /// A state that indicates the application isn’t authorized to use the Bluetooth low energy role.
    Unauthorized = 3,

    /// A state that indicates Bluetooth is currently powered off.
    PoweredOff = 4,

    /// A state that indicates Bluetooth is currently powered on and available to use.
    PoweredOn = 5,
}

impl ManagerState {
    fn from_u8(v: u8) -> Option<Self> {
        Some(match v {
            0 => Self::Unknown,
            1 => Self::Resetting,
            2 => Self::Unsupported,
            3 => Self::Unauthorized,
            4 => Self::PoweredOff,
            5 => Self::PoweredOn,
            _ => return None,
        })
    }
}