mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Integrate the devices
respository (#30974)
Despite the name of this dependency, it only handles bluetooth. Because it's a separate repository. Integrating it, allows changes here to be tested more consistently. In addition, it's likely that new bluetooth libraries will allow removing the majority of the platform-specific code in this directory. This is based on the version of this dependency from: https://github.com/servo/devices/pull/34
This commit is contained in:
parent
fddc4a430f
commit
6a804cd775
23 changed files with 3880 additions and 27 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -477,7 +477,10 @@ version = "0.0.1"
|
|||
dependencies = [
|
||||
"bitflags 2.4.1",
|
||||
"bluetooth_traits",
|
||||
"device",
|
||||
"blurdroid",
|
||||
"blurmac",
|
||||
"blurmock",
|
||||
"blurz",
|
||||
"embedder_traits",
|
||||
"ipc-channel",
|
||||
"log",
|
||||
|
@ -505,7 +508,6 @@ checksum = "19b23557dd27704797128f9db2816416bef20dad62d4a9768714eeb65f07d296"
|
|||
[[package]]
|
||||
name = "blurmac"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/servo/devices?rev=cb28c4725ffbfece99dab842d17d3e8c50774778#cb28c4725ffbfece99dab842d17d3e8c50774778"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objc",
|
||||
|
@ -1322,17 +1324,6 @@ dependencies = [
|
|||
"syn 1.0.103",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "device"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/servo/devices?rev=cb28c4725ffbfece99dab842d17d3e8c50774778#cb28c4725ffbfece99dab842d17d3e8c50774778"
|
||||
dependencies = [
|
||||
"blurdroid",
|
||||
"blurmac",
|
||||
"blurmock",
|
||||
"blurz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devtools"
|
||||
version = "0.0.1"
|
||||
|
|
|
@ -13,7 +13,7 @@ path = "lib.rs"
|
|||
[dependencies]
|
||||
bitflags = { workspace = true }
|
||||
bluetooth_traits = { workspace = true }
|
||||
device = { git = "https://github.com/servo/devices", features = ["bluetooth-test"], rev = "cb28c4725ffbfece99dab842d17d3e8c50774778" }
|
||||
blurmock = { version = "0.1.2", optional = true }
|
||||
embedder_traits = { workspace = true }
|
||||
ipc-channel = { workspace = true }
|
||||
log = { workspace = true }
|
||||
|
@ -22,4 +22,14 @@ servo_rand = { path = "../rand" }
|
|||
uuid = { workspace = true }
|
||||
|
||||
[features]
|
||||
native-bluetooth = ["device/bluetooth"]
|
||||
native-bluetooth = ["blurz", "blurdroid", "blurmac", "bluetooth-test"]
|
||||
bluetooth-test = ["blurmock"]
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
blurz = { version = "0.3", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
blurdroid = { version = "0.1.2", optional = true }
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
blurmac = { path = "../../third_party/blurmac", optional = true }
|
||||
|
|
55
components/bluetooth/README.md
Normal file
55
components/bluetooth/README.md
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Bluetooth Rust lib using macOS CoreBluetooth
|
||||
|
||||
[](https://travis-ci.org/akosthekiss/blurmac)
|
||||
[](https://crates.io/crates/blurmac)
|
||||
|
||||
The main aim of BlurMac is to enable [WebBluetooth](https://webbluetoothcg.github.io)
|
||||
in [Servo](https://github.com/servo/servo) on macOS. Thus, API and implementation
|
||||
decisions are affected by the encapsulating [Devices](https://github.com/servo/devices),
|
||||
and the sibling [BlurZ](https://github.com/szeged/blurz) and [BlurDroid](https://github.com/szeged/blurdroid)
|
||||
crates.
|
||||
|
||||
|
||||
## Run Servo with WebBluetooth Enabled
|
||||
|
||||
Usually, you don't want to work with BlurMac on its own but use it within Servo.
|
||||
So, most probably you'll want to run Servo with WebBluetooth enabled:
|
||||
|
||||
```
|
||||
RUST_LOG=blurmac \
|
||||
./mach run \
|
||||
--dev \
|
||||
--pref=dom.bluetooth.enabled \
|
||||
--pref=dom.permissions.testing.allowed_in_nonsecure_contexts \
|
||||
URL
|
||||
```
|
||||
|
||||
Notes:
|
||||
* The above command is actually not really BlurMac-specific (except for the `RUST_LOG`
|
||||
part). It runs Servo with WBT enabled on any platform where WBT is supported.
|
||||
* You don't need the `RUST_LOG=blurmac` part if you don't want to see BlurMac debug
|
||||
messages on the console.
|
||||
* You don't need the `--dev` part if you want to run a release build.
|
||||
* You don't need the `--pref=dom.permissions.testing.allowed_in_nonsecure_contexts`
|
||||
part if your `URL` is https (but you do need it if you test a local file).
|
||||
|
||||
|
||||
## Known Issues
|
||||
|
||||
* Device RSSI can not be retrieved yet.
|
||||
* Support for included services is incomplete.
|
||||
* Descriptors are not supported yet.
|
||||
* Notifications on characteristics are not supported yet (the limitation comes from
|
||||
Devices).
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
Tested on:
|
||||
|
||||
* macOS Sierra 10.12.
|
||||
|
||||
|
||||
## Copyright and Licensing
|
||||
|
||||
Licensed under the BSD 3-Clause [License](LICENSE.md).
|
408
components/bluetooth/adapter.rs
Normal file
408
components/bluetooth/adapter.rs
Normal file
|
@ -0,0 +1,408 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_adapter::Adapter as BluetoothAdapterAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_device::Device as BluetoothDeviceAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_discovery_session::DiscoverySession as BluetoothDiscoverySessionAndroid;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothAdapter as BluetoothAdapterMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothDevice as BluetoothDeviceMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothDiscoverySession as BluetoothDiscoverySessionMac;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_adapter::FakeBluetoothAdapter;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_device::FakeBluetoothDevice;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_adapter::BluetoothAdapter as BluetoothAdapterBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_device::BluetoothDevice as BluetoothDeviceBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as BluetoothDiscoverySessionBluez;
|
||||
|
||||
use super::bluetooth::{BluetoothDevice, BluetoothDiscoverySession};
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothDevice as BluetoothDeviceEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothDiscoverySession as BluetoothDiscoverySessionEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::EmptyAdapter as BluetoothAdapterEmpty;
|
||||
use super::macros::get_inner_and_call;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use super::macros::get_inner_and_call_test_func;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BluetoothAdapter {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothAdapterBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothAdapterAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothAdapterMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothAdapterEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothAdapter>),
|
||||
}
|
||||
|
||||
impl BluetoothAdapter {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
let bluez_adapter = BluetoothAdapterBluez::init()?;
|
||||
Ok(Self::Bluez(Arc::new(bluez_adapter)))
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
let blurdroid_adapter = BluetoothAdapterAndroid::get_adapter()?;
|
||||
Ok(Self::Android(Arc::new(blurdroid_adapter)))
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
let mac_adapter = BluetoothAdapterMac::init()?;
|
||||
Ok(Self::Mac(Arc::new(mac_adapter)))
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
pub fn new() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
let adapter = BluetoothAdapterEmpty::init()?;
|
||||
Ok(Self::Empty(Arc::new(adapter)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn new_mock() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
Ok(Self::Mock(FakeBluetoothAdapter::new_empty()))
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_id)
|
||||
}
|
||||
|
||||
pub fn get_devices(&self) -> Result<Vec<BluetoothDevice>, Box<dyn Error>> {
|
||||
match self {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Bluez(inner) => {
|
||||
let device_list = inner.get_device_list()?;
|
||||
Ok(device_list
|
||||
.into_iter()
|
||||
.map(|device| {
|
||||
BluetoothDevice::Bluez(BluetoothDeviceBluez::new_empty(
|
||||
self.0.clone(),
|
||||
device,
|
||||
))
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Android(inner) => {
|
||||
let device_list = inner.get_device_list()?;
|
||||
Ok(device_list
|
||||
.into_iter()
|
||||
.map(|device| {
|
||||
BluetoothDevice::Android(BluetoothDeviceAndroid::new_empty(
|
||||
self.0.clone(),
|
||||
device,
|
||||
))
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Mac(inner) => {
|
||||
let device_list = inner.get_device_list()?;
|
||||
Ok(device_list
|
||||
.into_iter()
|
||||
.map(|device| {
|
||||
BluetoothDevice::Mac(Arc::new(BluetoothDeviceMac::new(
|
||||
inner.clone(),
|
||||
device,
|
||||
)))
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
BluetoothAdapter::Empty(inner) => {
|
||||
let device_list = inner.get_device_list()?;
|
||||
Ok(device_list
|
||||
.into_iter()
|
||||
.map(|device| {
|
||||
BluetoothDevice::Empty(Arc::new(BluetoothDeviceEmpty::new(device)))
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothAdapter::Mock(inner) => {
|
||||
let device_list = inner.get_device_list()?;
|
||||
Ok(device_list
|
||||
.into_iter()
|
||||
.map(|device| {
|
||||
BluetoothDevice::Mock(FakeBluetoothDevice::new_empty(inner.clone(), device))
|
||||
})
|
||||
.collect())
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_device(&self, address: String) -> Result<Option<BluetoothDevice>, Box<dyn Error>> {
|
||||
let devices = self.get_devices()?;
|
||||
for device in devices {
|
||||
if device.get_address()? == address {
|
||||
return Ok(Some(device));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
pub fn create_mock_device(&self, _device: String) -> Result<BluetoothDevice, Box<dyn Error>> {
|
||||
match self {
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothAdapter::Mock(inner) => Ok(BluetoothDevice::Mock(
|
||||
FakeBluetoothDevice::new_empty(inner.clone(), _device),
|
||||
)),
|
||||
_ => Err(Box::from(
|
||||
"Error! Test functions are not supported on real devices!",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_discovery_session(&self) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
|
||||
let discovery_session = match self {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Bluez(inner) => {
|
||||
BluetoothDiscoverySession::Bluez(Arc::new(
|
||||
BluetoothDiscoverySessionBluez::create_session(inner.get_id())?,
|
||||
));
|
||||
},
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Android(inner) => BluetoothDiscoverySession::Android(Arc::new(
|
||||
BluetoothDiscoverySessionAndroid::create_session(inner.clone())?,
|
||||
)),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
BluetoothAdapter::Mac(_) => {
|
||||
BluetoothDiscoverySession::Mac(Arc::new(BluetoothDiscoverySessionMac {}))
|
||||
},
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
BluetoothAdapter::Empty(_) => {
|
||||
BluetoothDiscoverySession::Empty(Arc::new(BluetoothDiscoverySessionEmpty {}))
|
||||
},
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothAdapter::Mock(inner) => BluetoothDiscoverySession::Mock(Arc::new(
|
||||
FakeBluetoothDiscoverySession::create_session(inner.clone())?,
|
||||
)),
|
||||
};
|
||||
Ok(discovery_session)
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_address)
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_name)
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_alias)
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_class)
|
||||
}
|
||||
|
||||
pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, is_powered)
|
||||
}
|
||||
|
||||
pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, is_discoverable)
|
||||
}
|
||||
|
||||
pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, is_pairable)
|
||||
}
|
||||
|
||||
pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_pairable_timeout)
|
||||
}
|
||||
|
||||
pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_discoverable_timeout)
|
||||
}
|
||||
|
||||
pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, is_discovering)
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_uuids)
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_vendor_id_source)
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_vendor_id)
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_product_id)
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_device_id)
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothAdapter, get_modalias)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_id(&self, id: String) -> Result<(), Box<dyn Error>> {
|
||||
match self {
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothAdapter::Mock(inner) => Ok(inner.set_id(id)),
|
||||
_ => Err(Box::from(
|
||||
"Error! Test functions are not supported on real devices!",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_address(&self, address: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_address, address)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_name(&self, name: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_name, name)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_alias(&self, alias: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_alias, alias)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_class(&self, class: u32) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_class, class)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_powered(&self, powered: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_powered, powered)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn is_present(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, is_present)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_present(&self, present: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_present, present)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_discoverable(&self, discoverable: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable, discoverable)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_pairable(&self, pairable: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable, pairable)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_pairable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_pairable_timeout, timeout)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_can_start_discovery(&self, can_start_discovery: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(
|
||||
self,
|
||||
BluetoothAdapter,
|
||||
set_can_start_discovery,
|
||||
can_start_discovery
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_discoverable_timeout(&self, timeout: u32) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discoverable_timeout, timeout)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_discovering(&self, discovering: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_discovering, discovering)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_can_stop_discovery(&self, can_stop_discovery: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(
|
||||
self,
|
||||
BluetoothAdapter,
|
||||
set_can_stop_discovery,
|
||||
can_stop_discovery
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_uuids(&self, uuids: Vec<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_uuids, uuids)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_modalias(&self, modalias: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_modalias, modalias)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn get_ad_datas(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, get_ad_datas)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_ad_datas(&self, ad_datas: Vec<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothAdapter, set_ad_datas, ad_datas)
|
||||
}
|
||||
}
|
753
components/bluetooth/bluetooth.rs
Normal file
753
components/bluetooth/bluetooth.rs
Normal file
|
@ -0,0 +1,753 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_device::Device as BluetoothDeviceAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_discovery_session::DiscoverySession as BluetoothDiscoverySessionAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_gatt_characteristic::Characteristic as BluetoothGATTCharacteristicAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_gatt_descriptor::Descriptor as BluetoothGATTDescriptorAndroid;
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
use blurdroid::bluetooth_gatt_service::Service as BluetoothGATTServiceAndroid;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothDevice as BluetoothDeviceMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothDiscoverySession as BluetoothDiscoverySessionMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothGATTDescriptor as BluetoothGATTDescriptorMac;
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
use blurmac::BluetoothGATTService as BluetoothGATTServiceMac;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_characteristic::FakeBluetoothGATTCharacteristic;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_descriptor::FakeBluetoothGATTDescriptor;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_device::FakeBluetoothDevice;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_discovery_session::FakeBluetoothDiscoverySession;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use blurmock::fake_service::FakeBluetoothGATTService;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_device::BluetoothDevice as BluetoothDeviceBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_discovery_session::BluetoothDiscoverySession as BluetoothDiscoverySessionBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_gatt_characteristic::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_gatt_descriptor::BluetoothGATTDescriptor as BluetoothGATTDescriptorBluez;
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
use blurz::bluetooth_gatt_service::BluetoothGATTService as BluetoothGATTServiceBluez;
|
||||
|
||||
pub use super::adapter::BluetoothAdapter;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothDevice as BluetoothDeviceEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothDiscoverySession as BluetoothDiscoverySessionEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothGATTCharacteristic as BluetoothGATTCharacteristicEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothGATTDescriptor as BluetoothGATTDescriptorEmpty;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
use super::empty::BluetoothGATTService as BluetoothGATTServiceEmpty;
|
||||
use super::macros::get_inner_and_call;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
use super::macros::get_inner_and_call_test_func;
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
const NOT_SUPPORTED_ON_MOCK_ERROR: &'static str =
|
||||
"Error! The first parameter must be a mock structure!";
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BluetoothDiscoverySession {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothDiscoverySessionBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothDiscoverySessionAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothDiscoverySessionMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothDiscoverySessionEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothDiscoverySession>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BluetoothDevice {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothDeviceBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothDeviceAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothDeviceMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothDeviceEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothDevice>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BluetoothGATTService {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothGATTServiceBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothGATTServiceAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothGATTServiceMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothGATTServiceEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothGATTService>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BluetoothGATTCharacteristic {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothGATTCharacteristicBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothGATTCharacteristicAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothGATTCharacteristicMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothGATTCharacteristicEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothGATTCharacteristic>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum BluetoothGATTDescriptor {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
Bluez(Arc<BluetoothGATTDescriptorBluez>),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
Android(Arc<BluetoothGATTDescriptorAndroid>),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
Mac(Arc<BluetoothGATTDescriptorMac>),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
Empty(Arc<BluetoothGATTDescriptorEmpty>),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
Mock(Arc<FakeBluetoothGATTDescriptor>),
|
||||
}
|
||||
|
||||
impl BluetoothDiscoverySession {
|
||||
pub fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDiscoverySession, start_discovery)
|
||||
}
|
||||
|
||||
pub fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDiscoverySession, stop_discovery)
|
||||
}
|
||||
}
|
||||
|
||||
impl BluetoothDevice {
|
||||
pub fn get_id(&self) -> String {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_id(&self, id: String) {
|
||||
match self {
|
||||
&BluetoothDevice::Mock(ref fake_adapter) => fake_adapter.set_id(id),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_address)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_address(&self, address: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_address, address)
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_name)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_name(&self, name: Option<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_name, name)
|
||||
}
|
||||
|
||||
pub fn get_icon(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_icon)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_icon(&self, icon: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_icon, icon)
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_class)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_class(&self, class: u32) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_class, class)
|
||||
}
|
||||
|
||||
pub fn get_appearance(&self) -> Result<u16, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_appearance)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_appearance(&self, appearance: u16) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_appearance, Some(appearance))
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_uuids)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_uuids(&self, uuids: Vec<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_uuids, uuids)
|
||||
}
|
||||
|
||||
pub fn is_paired(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, is_paired)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_paired(&self, paired: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_paired, paired)
|
||||
}
|
||||
|
||||
pub fn is_connected(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, is_connected)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_connected(&self, connected: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_connected, connected)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn is_connectable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, is_connectable)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_connectable(&self, connectable: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_connectable, connectable)
|
||||
}
|
||||
|
||||
pub fn is_trusted(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, is_trusted)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_trusted(&self, trusted: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_trusted, trusted)
|
||||
}
|
||||
|
||||
pub fn is_blocked(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, is_blocked)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_blocked(&self, blocked: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_blocked, blocked)
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_alias)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_alias(&self, alias: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_alias, alias)
|
||||
}
|
||||
|
||||
pub fn is_legacy_pairing(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, is_legacy_pairing)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_legacy_pairing(&self, legacy_pairing: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_legacy_pairing, legacy_pairing)
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_vendor_id_source)
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_vendor_id)
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_product_id)
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_device_id)
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_modalias)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_modalias(&self, modalias: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_modalias, modalias)
|
||||
}
|
||||
|
||||
pub fn get_rssi(&self) -> Result<i16, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_rssi)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_rssi(&self, rssi: i16) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_rssi, Some(rssi))
|
||||
}
|
||||
|
||||
pub fn get_tx_power(&self) -> Result<i16, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_tx_power)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_tx_power(&self, tx_power: i16) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_tx_power, Some(tx_power))
|
||||
}
|
||||
|
||||
pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_manufacturer_data)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_manufacturer_data(
|
||||
&self,
|
||||
manufacturer_data: HashMap<u16, Vec<u8>>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(
|
||||
self,
|
||||
BluetoothDevice,
|
||||
set_manufacturer_data,
|
||||
Some(manufacturer_data)
|
||||
)
|
||||
}
|
||||
|
||||
pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, get_service_data)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_service_data(
|
||||
&self,
|
||||
service_data: HashMap<String, Vec<u8>>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothDevice, set_service_data, Some(service_data))
|
||||
}
|
||||
|
||||
pub fn get_gatt_services(&self) -> Result<Vec<BluetoothGATTService>, Box<dyn Error>> {
|
||||
let services = get_inner_and_call!(self, BluetoothDevice, get_gatt_services)?;
|
||||
Ok(services
|
||||
.into_iter()
|
||||
.map(|service| BluetoothGATTService::create_service(self.clone(), service))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn connect(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, connect)
|
||||
}
|
||||
|
||||
pub fn disconnect(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, disconnect)
|
||||
}
|
||||
|
||||
pub fn connect_profile(&self, uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, connect_profile, uuid)
|
||||
}
|
||||
|
||||
pub fn disconnect_profile(&self, uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, disconnect_profile, uuid)
|
||||
}
|
||||
|
||||
pub fn pair(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, pair)
|
||||
}
|
||||
|
||||
pub fn cancel_pairing(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothDevice, cancel_pairing)
|
||||
}
|
||||
}
|
||||
|
||||
impl BluetoothGATTService {
|
||||
fn create_service(device: BluetoothDevice, service: String) -> BluetoothGATTService {
|
||||
match device {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
BluetoothDevice::Bluez(_bluez_device) => {
|
||||
BluetoothGATTService::Bluez(Arc::new(BluetoothGATTServiceBluez::new(service)))
|
||||
},
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
BluetoothDevice::Android(android_device) => BluetoothGATTService::Android(Arc::new(
|
||||
BluetoothGATTServiceAndroid::new(android_device, service),
|
||||
)),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
BluetoothDevice::Mac(mac_device) => BluetoothGATTService::Mac(Arc::new(
|
||||
BluetoothGATTServiceMac::new(mac_device, service),
|
||||
)),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
BluetoothDevice::Empty(_device) => {
|
||||
BluetoothGATTService::Empty(Arc::new(BluetoothGATTServiceEmpty::new(service)))
|
||||
},
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothDevice::Mock(fake_device) => BluetoothGATTService::Mock(
|
||||
FakeBluetoothGATTService::new_empty(fake_device, service),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn create_mock_service(
|
||||
device: BluetoothDevice,
|
||||
service: String,
|
||||
) -> Result<BluetoothGATTService, Box<dyn Error>> {
|
||||
match device {
|
||||
BluetoothDevice::Mock(fake_device) => Ok(BluetoothGATTService::Mock(
|
||||
FakeBluetoothGATTService::new_empty(fake_device, service),
|
||||
)),
|
||||
_ => Err(Box::from(
|
||||
"Error! The first parameter must be a mock structure!",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
get_inner_and_call!(self, BluetoothGATTService, get_id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_id(&self, id: String) {
|
||||
match self {
|
||||
&BluetoothGATTService::Mock(ref fake_service) => fake_service.set_id(id),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTService, get_uuid)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTService, set_uuid, uuid)
|
||||
}
|
||||
|
||||
pub fn is_primary(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTService, is_primary)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_primary(&self, primary: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTService, set_is_primary, primary)
|
||||
}
|
||||
|
||||
pub fn get_includes(
|
||||
&self,
|
||||
device: BluetoothDevice,
|
||||
) -> Result<Vec<BluetoothGATTService>, Box<dyn Error>> {
|
||||
let services = get_inner_and_call!(self, BluetoothGATTService, get_includes)?;
|
||||
Ok(services
|
||||
.into_iter()
|
||||
.map(|service| BluetoothGATTService::create_service(device.clone(), service))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn get_gatt_characteristics(
|
||||
&self,
|
||||
) -> Result<Vec<BluetoothGATTCharacteristic>, Box<dyn Error>> {
|
||||
let characteristics =
|
||||
get_inner_and_call!(self, BluetoothGATTService, get_gatt_characteristics)?;
|
||||
Ok(characteristics
|
||||
.into_iter()
|
||||
.map(|characteristic| {
|
||||
BluetoothGATTCharacteristic::create_characteristic(self.clone(), characteristic)
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl BluetoothGATTCharacteristic {
|
||||
fn create_characteristic(
|
||||
service: BluetoothGATTService,
|
||||
characteristic: String,
|
||||
) -> BluetoothGATTCharacteristic {
|
||||
match service {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
BluetoothGATTService::Bluez(_bluez_service) => BluetoothGATTCharacteristic::Bluez(
|
||||
Arc::new(BluetoothGATTCharacteristicBluez::new(characteristic)),
|
||||
),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
BluetoothGATTService::Android(android_service) => {
|
||||
BluetoothGATTCharacteristic::Android(Arc::new(
|
||||
BluetoothGATTCharacteristicAndroid::new(android_service, characteristic),
|
||||
))
|
||||
},
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
BluetoothGATTService::Mac(mac_service) => BluetoothGATTCharacteristic::Mac(Arc::new(
|
||||
BluetoothGATTCharacteristicMac::new(mac_service, characteristic),
|
||||
)),
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
BluetoothGATTService::Empty(_service) => BluetoothGATTCharacteristic::Empty(Arc::new(
|
||||
BluetoothGATTCharacteristicEmpty::new(characteristic),
|
||||
)),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothGATTService::Mock(fake_service) => BluetoothGATTCharacteristic::Mock(
|
||||
FakeBluetoothGATTCharacteristic::new_empty(fake_service, characteristic),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn create_mock_characteristic(
|
||||
service: BluetoothGATTService,
|
||||
characteristic: String,
|
||||
) -> Result<BluetoothGATTCharacteristic, Box<dyn Error>> {
|
||||
match service {
|
||||
BluetoothGATTService::Mock(fake_service) => Ok(BluetoothGATTCharacteristic::Mock(
|
||||
FakeBluetoothGATTCharacteristic::new_empty(fake_service, characteristic),
|
||||
)),
|
||||
_ => Err(Box::from(
|
||||
"Error! The first parameter must be a mock structure!",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_id(&self, id: String) {
|
||||
match self {
|
||||
&BluetoothGATTCharacteristic::Mock(ref fake_characteristic) => {
|
||||
fake_characteristic.set_id(id)
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_uuid)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_uuid, uuid)
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_value)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_value(&self, value: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_value, Some(value))
|
||||
}
|
||||
|
||||
pub fn is_notifying(&self) -> Result<bool, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, is_notifying)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_notifying(&self, notifying: bool) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_notifying, notifying)
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_flags)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_flags(&self, flags: Vec<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTCharacteristic, set_flags, flags)
|
||||
}
|
||||
|
||||
pub fn get_gatt_descriptors(&self) -> Result<Vec<BluetoothGATTDescriptor>, Box<dyn Error>> {
|
||||
let descriptors =
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, get_gatt_descriptors)?;
|
||||
Ok(descriptors
|
||||
.into_iter()
|
||||
.map(|descriptor| BluetoothGATTDescriptor::create_descriptor(self.clone(), descriptor))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTCharacteristic, read_value)
|
||||
}
|
||||
|
||||
pub fn write_value(&self, values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTCharacteristic, write_value, values)
|
||||
}
|
||||
|
||||
pub fn start_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, start_notify)
|
||||
}
|
||||
|
||||
pub fn stop_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTCharacteristic, stop_notify)
|
||||
}
|
||||
}
|
||||
|
||||
impl BluetoothGATTDescriptor {
|
||||
fn create_descriptor(
|
||||
characteristic: BluetoothGATTCharacteristic,
|
||||
descriptor: String,
|
||||
) -> BluetoothGATTDescriptor {
|
||||
match characteristic {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
BluetoothGATTCharacteristic::Bluez(_bluez_characteristic) => {
|
||||
BluetoothGATTDescriptor::Bluez(Arc::new(BluetoothGATTDescriptorBluez::new(
|
||||
descriptor,
|
||||
)))
|
||||
},
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
BluetoothGATTCharacteristic::Android(android_characteristic) => {
|
||||
BluetoothGATTDescriptor::Android(Arc::new(BluetoothGATTDescriptorAndroid::new(
|
||||
android_characteristic,
|
||||
descriptor,
|
||||
)))
|
||||
},
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
BluetoothGATTCharacteristic::Mac(_mac_characteristic) => {
|
||||
BluetoothGATTDescriptor::Mac(Arc::new(BluetoothGATTDescriptorMac::new(descriptor)))
|
||||
},
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
BluetoothGATTCharacteristic::Empty(_characteristic) => BluetoothGATTDescriptor::Empty(
|
||||
Arc::new(BluetoothGATTDescriptorEmpty::new(descriptor)),
|
||||
),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
BluetoothGATTCharacteristic::Mock(fake_characteristic) => {
|
||||
BluetoothGATTDescriptor::Mock(FakeBluetoothGATTDescriptor::new_empty(
|
||||
fake_characteristic,
|
||||
descriptor,
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn create_mock_descriptor(
|
||||
characteristic: BluetoothGATTCharacteristic,
|
||||
descriptor: String,
|
||||
) -> Result<BluetoothGATTDescriptor, Box<dyn Error>> {
|
||||
match characteristic {
|
||||
BluetoothGATTCharacteristic::Mock(fake_characteristic) => {
|
||||
Ok(BluetoothGATTDescriptor::Mock(
|
||||
FakeBluetoothGATTDescriptor::new_empty(fake_characteristic, descriptor),
|
||||
))
|
||||
},
|
||||
_ => Err(Box::from(NOT_SUPPORTED_ON_MOCK_ERROR)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
get_inner_and_call!(self, BluetoothGATTDescriptor, get_id)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_id(&self, id: String) {
|
||||
match self {
|
||||
&BluetoothGATTDescriptor::Mock(ref fake_descriptor) => fake_descriptor.set_id(id),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTDescriptor, get_uuid)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_uuid(&self, uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_uuid, uuid)
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTDescriptor, get_value)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_value(&self, value: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_value, Some(value))
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
get_inner_and_call!(self, BluetoothGATTDescriptor, get_flags)
|
||||
}
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub fn set_flags(&self, flags: Vec<String>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call_test_func!(self, BluetoothGATTDescriptor, set_flags, flags)
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTDescriptor, read_value)
|
||||
}
|
||||
|
||||
pub fn write_value(&self, values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
get_inner_and_call!(@with_bluez_offset, self, BluetoothGATTDescriptor, write_value, values)
|
||||
}
|
||||
}
|
377
components/bluetooth/empty.rs
Normal file
377
components/bluetooth/empty.rs
Normal file
|
@ -0,0 +1,377 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
const NOT_SUPPORTED_ERROR: &'static str = "Error! Not supported platform!";
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EmptyAdapter {}
|
||||
|
||||
impl EmptyAdapter {
|
||||
pub fn init() -> Result<EmptyAdapter, Box<dyn Error>> {
|
||||
Ok(EmptyAdapter::new())
|
||||
}
|
||||
|
||||
fn new() -> EmptyAdapter {
|
||||
EmptyAdapter {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_device_list(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_powered(&self, _value: bool) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_discoverable(&self, _value: bool) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_pairable(&self, _value: bool) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_pairable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_discoverable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothDiscoverySession {}
|
||||
|
||||
impl BluetoothDiscoverySession {
|
||||
pub fn create_session(
|
||||
_adapter: Arc<EmptyAdapter>,
|
||||
) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
|
||||
Ok(BluetoothDiscoverySession {})
|
||||
}
|
||||
|
||||
pub fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothDevice {}
|
||||
|
||||
impl BluetoothDevice {
|
||||
pub fn new(_device: String) -> BluetoothDevice {
|
||||
BluetoothDevice {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_icon(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_appearance(&self) -> Result<u16, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_paired(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_connected(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_trusted(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_blocked(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_legacy_pairing(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_rssi(&self) -> Result<i16, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_tx_power(&self) -> Result<i16, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn connect(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn disconnect(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn connect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn disconnect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn pair(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn cancel_pairing(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTService {}
|
||||
|
||||
impl BluetoothGATTService {
|
||||
pub fn new(_service: String) -> BluetoothGATTService {
|
||||
BluetoothGATTService {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_primary(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_includes(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_gatt_characteristics(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTCharacteristic {}
|
||||
|
||||
impl BluetoothGATTCharacteristic {
|
||||
pub fn new(_characteristic: String) -> BluetoothGATTCharacteristic {
|
||||
BluetoothGATTCharacteristic {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_notifying(&self) -> Result<bool, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_gatt_descriptors(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn write_value(&self, _values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn start_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn stop_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTDescriptor {}
|
||||
|
||||
impl BluetoothGATTDescriptor {
|
||||
pub fn new(_descriptor: String) -> BluetoothGATTDescriptor {
|
||||
BluetoothGATTDescriptor {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn write_value(&self, _values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
|
@ -2,6 +2,15 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
pub mod adapter;
|
||||
pub mod bluetooth;
|
||||
#[cfg(not(any(
|
||||
all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth")
|
||||
)))]
|
||||
mod empty;
|
||||
mod macros;
|
||||
pub mod test;
|
||||
|
||||
use std::borrow::ToOwned;
|
||||
|
@ -20,16 +29,17 @@ use bluetooth_traits::{
|
|||
BluetoothRequest, BluetoothResponse, BluetoothResponseResult, BluetoothResult,
|
||||
BluetoothServiceMsg, GATTType,
|
||||
};
|
||||
use device::bluetooth::{
|
||||
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
|
||||
BluetoothGATTService,
|
||||
};
|
||||
use embedder_traits::{EmbedderMsg, EmbedderProxy};
|
||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||
use log::warn;
|
||||
use servo_config::pref;
|
||||
use servo_rand::{self, Rng};
|
||||
|
||||
use crate::bluetooth::{
|
||||
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
|
||||
BluetoothGATTService,
|
||||
};
|
||||
|
||||
// A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed.
|
||||
// https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480)
|
||||
const MAXIMUM_TRANSACTION_TIME: u8 = 30;
|
||||
|
@ -67,9 +77,9 @@ impl BluetoothThreadFactory for IpcSender<BluetoothRequest> {
|
|||
fn new(embedder_proxy: EmbedderProxy) -> IpcSender<BluetoothRequest> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
let adapter = if pref!(dom.bluetooth.enabled) {
|
||||
BluetoothAdapter::init()
|
||||
BluetoothAdapter::new()
|
||||
} else {
|
||||
BluetoothAdapter::init_mock()
|
||||
BluetoothAdapter::new_mock()
|
||||
}
|
||||
.ok();
|
||||
thread::Builder::new()
|
||||
|
@ -287,7 +297,7 @@ impl BluetoothManager {
|
|||
self.cached_characteristics.clear();
|
||||
self.cached_descriptors.clear();
|
||||
self.allowed_services.clear();
|
||||
self.adapter = BluetoothAdapter::init_mock().ok();
|
||||
self.adapter = BluetoothAdapter::new_mock().ok();
|
||||
match test::test(self, data_set_name) {
|
||||
Ok(_) => return Ok(()),
|
||||
Err(error) => Err(BluetoothError::Type(error.to_string())),
|
||||
|
@ -324,7 +334,7 @@ impl BluetoothManager {
|
|||
.as_ref()
|
||||
.map_or(false, |a| a.get_address().is_ok());
|
||||
if !adapter_valid {
|
||||
self.adapter = BluetoothAdapter::init().ok();
|
||||
self.adapter = BluetoothAdapter::new().ok();
|
||||
}
|
||||
|
||||
let adapter = self.adapter.as_ref()?;
|
||||
|
|
98
components/bluetooth/macros.rs
Normal file
98
components/bluetooth/macros.rs
Normal file
|
@ -0,0 +1,98 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
macro_rules! get_inner_and_call(
|
||||
($enum_value: expr, $enum_type: ident, $function_name: ident) => {
|
||||
match $enum_value {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
&$enum_type::Bluez(ref bluez) => bluez.$function_name(),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
&$enum_type::Android(ref android) => android.$function_name(),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
&$enum_type::Mac(ref mac) => mac.$function_name(),
|
||||
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth"))))]
|
||||
&$enum_type::Empty(ref empty) => empty.$function_name(),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name(),
|
||||
}
|
||||
};
|
||||
|
||||
(@with_bluez_offset, $enum_value: expr, $enum_type: ident, $function_name: ident) => {
|
||||
match $enum_value {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
&$enum_type::Bluez(ref bluez) => bluez.$function_name(None),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
&$enum_type::Android(ref android) => android.$function_name(),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
&$enum_type::Mac(ref mac) => mac.$function_name(),
|
||||
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth"))))]
|
||||
&$enum_type::Empty(ref empty) => empty.$function_name(),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name(),
|
||||
}
|
||||
};
|
||||
|
||||
($enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
|
||||
match $enum_value {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
&$enum_type::Bluez(ref bluez) => bluez.$function_name($value),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
&$enum_type::Android(ref android) => android.$function_name($value),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
&$enum_type::Mac(ref mac) => mac.$function_name($value),
|
||||
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth"))))]
|
||||
&$enum_type::Empty(ref empty) => empty.$function_name($value),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name($value),
|
||||
}
|
||||
};
|
||||
|
||||
(@with_bluez_offset, $enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
|
||||
match $enum_value {
|
||||
#[cfg(all(target_os = "linux", feature = "bluetooth"))]
|
||||
&$enum_type::Bluez(ref bluez) => bluez.$function_name($value, None),
|
||||
#[cfg(all(target_os = "android", feature = "bluetooth"))]
|
||||
&$enum_type::Android(ref android) => android.$function_name($value),
|
||||
#[cfg(all(target_os = "macos", feature = "bluetooth"))]
|
||||
&$enum_type::Mac(ref mac) => mac.$function_name($value),
|
||||
#[cfg(not(any(all(target_os = "linux", feature = "bluetooth"),
|
||||
all(target_os = "android", feature = "bluetooth"),
|
||||
all(target_os = "macos", feature = "bluetooth"))))]
|
||||
&$enum_type::Empty(ref empty) => empty.$function_name($value),
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name($value),
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
macro_rules! get_inner_and_call_test_func {
|
||||
($enum_value: expr, $enum_type: ident, $function_name: ident, $value: expr) => {
|
||||
match $enum_value {
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name($value),
|
||||
_ => Err(Box::from(
|
||||
"Error! Test functions are not supported on real devices!",
|
||||
)),
|
||||
}
|
||||
};
|
||||
|
||||
($enum_value: expr, $enum_type: ident, $function_name: ident) => {
|
||||
match $enum_value {
|
||||
&$enum_type::Mock(ref fake) => fake.$function_name(),
|
||||
_ => Err(Box::from(
|
||||
"Error! Test functions are not supported on real devices!",
|
||||
)),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use get_inner_and_call;
|
||||
#[cfg(feature = "bluetooth-test")]
|
||||
pub(crate) use get_inner_and_call_test_func;
|
|
@ -8,12 +8,12 @@ use std::collections::{HashMap, HashSet};
|
|||
use std::error::Error;
|
||||
use std::string::String;
|
||||
|
||||
use device::bluetooth::{
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::bluetooth::{
|
||||
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
|
||||
BluetoothGATTService,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::BluetoothManager;
|
||||
|
||||
thread_local!(pub static CACHED_IDS: RefCell<HashSet<Uuid>> = RefCell::new(HashSet::new()));
|
||||
|
@ -152,7 +152,7 @@ fn create_device(
|
|||
name: String,
|
||||
address: String,
|
||||
) -> Result<BluetoothDevice, Box<dyn Error>> {
|
||||
let device = BluetoothDevice::create_mock_device(adapter.clone(), generate_id().to_string())?;
|
||||
let device = adapter.create_mock_device(generate_id().to_string())?;
|
||||
device.set_name(Some(name))?;
|
||||
device.set_address(address)?;
|
||||
device.set_connectable(true)?;
|
||||
|
|
41
third_party/blurmac/Cargo.lock
generated
vendored
Normal file
41
third_party/blurmac/Cargo.lock
generated
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "blurmac"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||
dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
18
third_party/blurmac/Cargo.toml
vendored
Normal file
18
third_party/blurmac/Cargo.toml
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
[package]
|
||||
name = "blurmac"
|
||||
description = "Bluetooth Rust lib using macOS CoreBluetooth"
|
||||
version = "0.1.0"
|
||||
readme = "README.md"
|
||||
keywords = ["bluetooth", "ble", "macOS", "CoreBluetooth"]
|
||||
repository = "https://github.com/akosthekiss/blurmac"
|
||||
authors = ["Akos Kiss <akiss@inf.u-szeged.hu>"]
|
||||
license = "BSD-3-Clause"
|
||||
|
||||
[lib]
|
||||
name = "blurmac"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["rlib"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
objc = "0.2"
|
27
third_party/blurmac/LICENSE.md
vendored
Normal file
27
third_party/blurmac/LICENSE.md
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2017 Akos Kiss.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
55
third_party/blurmac/README.md
vendored
Normal file
55
third_party/blurmac/README.md
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
# Bluetooth Rust lib using macOS CoreBluetooth
|
||||
|
||||
[](https://travis-ci.org/akosthekiss/blurmac)
|
||||
[](https://crates.io/crates/blurmac)
|
||||
|
||||
The main aim of BlurMac is to enable [WebBluetooth](https://webbluetoothcg.github.io)
|
||||
in [Servo](https://github.com/servo/servo) on macOS. Thus, API and implementation
|
||||
decisions are affected by the encapsulating [Devices](https://github.com/servo/devices),
|
||||
and the sibling [BlurZ](https://github.com/szeged/blurz) and [BlurDroid](https://github.com/szeged/blurdroid)
|
||||
crates.
|
||||
|
||||
|
||||
## Run Servo with WebBluetooth Enabled
|
||||
|
||||
Usually, you don't want to work with BlurMac on its own but use it within Servo.
|
||||
So, most probably you'll want to run Servo with WebBluetooth enabled:
|
||||
|
||||
```
|
||||
RUST_LOG=blurmac \
|
||||
./mach run \
|
||||
--dev \
|
||||
--pref=dom.bluetooth.enabled \
|
||||
--pref=dom.permissions.testing.allowed_in_nonsecure_contexts \
|
||||
URL
|
||||
```
|
||||
|
||||
Notes:
|
||||
* The above command is actually not really BlurMac-specific (except for the `RUST_LOG`
|
||||
part). It runs Servo with WBT enabled on any platform where WBT is supported.
|
||||
* You don't need the `RUST_LOG=blurmac` part if you don't want to see BlurMac debug
|
||||
messages on the console.
|
||||
* You don't need the `--dev` part if you want to run a release build.
|
||||
* You don't need the `--pref=dom.permissions.testing.allowed_in_nonsecure_contexts`
|
||||
part if your `URL` is https (but you do need it if you test a local file).
|
||||
|
||||
|
||||
## Known Issues
|
||||
|
||||
* Device RSSI can not be retrieved yet.
|
||||
* Support for included services is incomplete.
|
||||
* Descriptors are not supported yet.
|
||||
* Notifications on characteristics are not supported yet (the limitation comes from
|
||||
Devices).
|
||||
|
||||
|
||||
## Compatibility
|
||||
|
||||
Tested on:
|
||||
|
||||
* macOS Sierra 10.12.
|
||||
|
||||
|
||||
## Copyright and Licensing
|
||||
|
||||
Licensed under the BSD 3-Clause [License](LICENSE.md).
|
212
third_party/blurmac/src/adapter.rs
vendored
Normal file
212
third_party/blurmac/src/adapter.rs
vendored
Normal file
|
@ -0,0 +1,212 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use delegate::bm;
|
||||
use framework::{cb, io, ns};
|
||||
use objc::runtime::{Object, YES};
|
||||
use utils::{nsx, NOT_SUPPORTED_ERROR};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothAdapter {
|
||||
pub(crate) manager: *mut Object,
|
||||
pub(crate) delegate: *mut Object,
|
||||
}
|
||||
// TODO: implement std::fmt::Debug and/or std::fmt::Display instead of derive?
|
||||
|
||||
unsafe impl Send for BluetoothAdapter {}
|
||||
unsafe impl Sync for BluetoothAdapter {}
|
||||
|
||||
impl BluetoothAdapter {
|
||||
pub fn init() -> Result<BluetoothAdapter, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::init");
|
||||
let delegate = bm::delegate();
|
||||
let manager = cb::centralmanager(delegate);
|
||||
let adapter = BluetoothAdapter {
|
||||
manager: manager,
|
||||
delegate: delegate,
|
||||
};
|
||||
|
||||
// NOTE: start discovery at once, servo leaves close to no time to do a proper discovery
|
||||
// in a BluetoothDiscoverySession
|
||||
adapter.start_discovery().unwrap();
|
||||
|
||||
Ok(adapter)
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
trace!("BluetoothAdapter::get_id");
|
||||
// NOTE: not aware of any better native ID than the address string
|
||||
self.get_address().unwrap()
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::get_name");
|
||||
let controller = io::bluetoothhostcontroller_defaultcontroller();
|
||||
let name = io::bluetoothhostcontroller_nameasstring(controller);
|
||||
Ok(nsx::string_to_string(name))
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::get_address");
|
||||
let controller = io::bluetoothhostcontroller_defaultcontroller();
|
||||
let address = io::bluetoothhostcontroller_addressasstring(controller);
|
||||
Ok(nsx::string_to_string(address))
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::get_class");
|
||||
let controller = io::bluetoothhostcontroller_defaultcontroller();
|
||||
let device_class = io::bluetoothhostcontroller_classofdevice(controller);
|
||||
Ok(device_class)
|
||||
}
|
||||
|
||||
pub fn is_powered(&self) -> Result<bool, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::is_powered");
|
||||
// NOTE: might be also available through
|
||||
// [[IOBluetoothHostController defaultController] powerState], but that's readonly, so keep
|
||||
// it in sync with set_powered
|
||||
Ok(io::bluetoothpreferencegetcontrollerpowerstate() == 1)
|
||||
}
|
||||
|
||||
pub fn set_powered(&self, value: bool) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::set_powered");
|
||||
io::bluetoothpreferencesetcontrollerpowerstate(value as c_int);
|
||||
// TODO: wait for change to happen? whether it really happened?
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_discoverable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::is_discoverable");
|
||||
Ok(io::bluetoothpreferencegetdiscoverablestate() == 1)
|
||||
}
|
||||
|
||||
pub fn set_discoverable(&self, value: bool) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::set_discoverable");
|
||||
io::bluetoothpreferencesetdiscoverablestate(value as c_int);
|
||||
// TODO: wait for change to happen? whether it really happened?
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_device_list(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::get_device_list");
|
||||
let mut v = vec![];
|
||||
let peripherals = bm::delegate_peripherals(self.delegate);
|
||||
let keys = ns::dictionary_allkeys(peripherals);
|
||||
for i in 0..ns::array_count(keys) {
|
||||
v.push(nsx::string_to_string(ns::array_objectatindex(keys, i)));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
// Was in BluetoothDiscoverySession
|
||||
|
||||
fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::start_discovery");
|
||||
let options = ns::mutabledictionary();
|
||||
// NOTE: If duplicates are not allowed then a peripheral will not show up again once
|
||||
// connected and then disconnected.
|
||||
ns::mutabledictionary_setobject_forkey(options, ns::number_withbool(YES), unsafe {
|
||||
cb::CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY
|
||||
});
|
||||
cb::centralmanager_scanforperipherals_options(self.manager, options);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothAdapter::stop_discovery");
|
||||
cb::centralmanager_stopscan(self.manager);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Not supported
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_alias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::set_alias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_pairable(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::is_pairable not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_pairable(&self, _value: bool) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::set_pairable not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_pairable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_pairable_timeout not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_pairable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::set_pairable_timeout not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_discoverable_timeout(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_discoverable_timeout not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_discoverable_timeout(&self, _value: u32) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::set_discoverable_timeout not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_discovering(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::is_discovering not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_uuids not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_vendor_id_source not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_vendor_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_product_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_device_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
warn!("BluetoothAdapter::get_modalias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BluetoothAdapter {
|
||||
fn drop(&mut self) {
|
||||
trace!("BluetoothAdapter::drop");
|
||||
// NOTE: stop discovery only here instead of in BluetoothDiscoverySession
|
||||
self.stop_discovery().unwrap();
|
||||
}
|
||||
}
|
443
third_party/blurmac/src/delegate.rs
vendored
Normal file
443
third_party/blurmac/src/delegate.rs
vendored
Normal file
|
@ -0,0 +1,443 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::sync::Once;
|
||||
|
||||
use framework::{cb, nil, ns};
|
||||
use objc::declare::ClassDecl;
|
||||
use objc::runtime::{Class, Object, Protocol, Sel};
|
||||
use utils::{cbx, nsx, wait, NO_PERIPHERAL_FOUND};
|
||||
|
||||
pub mod bm {
|
||||
use super::*;
|
||||
|
||||
// BlurMacDelegate : CBCentralManagerDelegate, CBPeripheralDelegate
|
||||
|
||||
const DELEGATE_PERIPHERALS_IVAR: &'static str = "_peripherals";
|
||||
|
||||
fn delegate_class() -> &'static Class {
|
||||
trace!("delegate_class");
|
||||
static REGISTER_DELEGATE_CLASS: Once = Once::new();
|
||||
|
||||
REGISTER_DELEGATE_CLASS.call_once(|| {
|
||||
let mut decl = ClassDecl::new("BlurMacDelegate", Class::get("NSObject").unwrap()).unwrap();
|
||||
decl.add_protocol(Protocol::get("CBCentralManagerDelegate").unwrap());
|
||||
|
||||
decl.add_ivar::<*mut Object>(DELEGATE_PERIPHERALS_IVAR); /* NSMutableDictionary<NSString*, BlurMacPeripheralData*>* */
|
||||
|
||||
unsafe {
|
||||
decl.add_method(sel!(init), delegate_init as extern fn(&mut Object, Sel) -> *mut Object);
|
||||
decl.add_method(sel!(centralManagerDidUpdateState:), delegate_centralmanagerdidupdatestate as extern fn(&mut Object, Sel, *mut Object));
|
||||
// decl.add_method(sel!(centralManager:willRestoreState:), delegate_centralmanager_willrestorestate as extern fn(&mut Object, Sel, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(centralManager:didConnectPeripheral:), delegate_centralmanager_didconnectperipheral as extern fn(&mut Object, Sel, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(centralManager:didDisconnectPeripheral:error:), delegate_centralmanager_diddisconnectperipheral_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
// decl.add_method(sel!(centralManager:didFailToConnectPeripheral:error:), delegate_centralmanager_didfailtoconnectperipheral_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(centralManager:didDiscoverPeripheral:advertisementData:RSSI:), delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object, *mut Object));
|
||||
|
||||
decl.add_method(sel!(peripheral:didDiscoverServices:), delegate_peripheral_diddiscoverservices as extern fn(&mut Object, Sel, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(peripheral:didDiscoverIncludedServicesForService:error:), delegate_peripheral_diddiscoverincludedservicesforservice_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(peripheral:didDiscoverCharacteristicsForService:error:), delegate_peripheral_diddiscovercharacteristicsforservice_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(peripheral:didUpdateValueForCharacteristic:error:), delegate_peripheral_didupdatevalueforcharacteristic_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(peripheral:didWriteValueForCharacteristic:error:), delegate_peripheral_didwritevalueforcharacteristic_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
decl.add_method(sel!(peripheral:didReadRSSI:error:), delegate_peripheral_didreadrssi_error as extern fn(&mut Object, Sel, *mut Object, *mut Object, *mut Object));
|
||||
}
|
||||
|
||||
decl.register();
|
||||
});
|
||||
|
||||
Class::get("BlurMacDelegate").unwrap()
|
||||
}
|
||||
|
||||
extern "C" fn delegate_init(delegate: &mut Object, _cmd: Sel) -> *mut Object {
|
||||
trace!("delegate_init");
|
||||
unsafe {
|
||||
delegate.set_ivar::<*mut Object>(DELEGATE_PERIPHERALS_IVAR, ns::mutabledictionary());
|
||||
}
|
||||
delegate
|
||||
}
|
||||
|
||||
extern "C" fn delegate_centralmanagerdidupdatestate(
|
||||
_delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
_central: *mut Object,
|
||||
) {
|
||||
trace!("delegate_centralmanagerdidupdatestate");
|
||||
// NOTE: this is a no-op but kept because it is a required method of the protocol
|
||||
}
|
||||
|
||||
// extern fn delegate_centralmanager_willrestorestate(_delegate: &mut Object, _cmd: Sel, _central: *mut Object, _dict: *mut Object) {
|
||||
// trace!("delegate_centralmanager_willrestorestate");
|
||||
// }
|
||||
|
||||
extern "C" fn delegate_centralmanager_didconnectperipheral(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
_central: *mut Object,
|
||||
peripheral: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_centralmanager_didconnectperipheral {}",
|
||||
cbx::peripheral_debug(peripheral)
|
||||
);
|
||||
cb::peripheral_setdelegate(peripheral, delegate);
|
||||
cb::peripheral_discoverservices(peripheral);
|
||||
}
|
||||
|
||||
extern "C" fn delegate_centralmanager_diddisconnectperipheral_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
_central: *mut Object,
|
||||
peripheral: *mut Object,
|
||||
_error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_centralmanager_diddisconnectperipheral_error {}",
|
||||
cbx::peripheral_debug(peripheral)
|
||||
);
|
||||
ns::mutabledictionary_removeobjectforkey(
|
||||
delegate_peripherals(delegate),
|
||||
ns::uuid_uuidstring(cb::peer_identifier(peripheral)),
|
||||
);
|
||||
}
|
||||
|
||||
// extern fn delegate_centralmanager_didfailtoconnectperipheral_error(_delegate: &mut Object, _cmd: Sel, _central: *mut Object, _peripheral: *mut Object, _error: *mut Object) {
|
||||
// trace!("delegate_centralmanager_didfailtoconnectperipheral_error");
|
||||
// }
|
||||
|
||||
extern "C" fn delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
_central: *mut Object,
|
||||
peripheral: *mut Object,
|
||||
adv_data: *mut Object,
|
||||
rssi: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_centralmanager_diddiscoverperipheral_advertisementdata_rssi {}",
|
||||
cbx::peripheral_debug(peripheral)
|
||||
);
|
||||
let peripherals = delegate_peripherals(delegate);
|
||||
let uuid_nsstring = ns::uuid_uuidstring(cb::peer_identifier(peripheral));
|
||||
let mut data = ns::dictionary_objectforkey(peripherals, uuid_nsstring);
|
||||
if data == nil {
|
||||
data = ns::mutabledictionary();
|
||||
ns::mutabledictionary_setobject_forkey(peripherals, data, uuid_nsstring);
|
||||
}
|
||||
|
||||
ns::mutabledictionary_setobject_forkey(
|
||||
data,
|
||||
ns::object_copy(peripheral),
|
||||
nsx::string_from_str(PERIPHERALDATA_PERIPHERALKEY),
|
||||
);
|
||||
|
||||
ns::mutabledictionary_setobject_forkey(
|
||||
data,
|
||||
rssi,
|
||||
nsx::string_from_str(PERIPHERALDATA_RSSIKEY),
|
||||
);
|
||||
|
||||
let cbuuids_nsarray =
|
||||
ns::dictionary_objectforkey(adv_data, unsafe { cb::ADVERTISEMENTDATASERVICEUUIDSKEY });
|
||||
if cbuuids_nsarray != nil {
|
||||
ns::mutabledictionary_setobject_forkey(
|
||||
data,
|
||||
cbuuids_nsarray,
|
||||
nsx::string_from_str(PERIPHERALDATA_UUIDSKEY),
|
||||
);
|
||||
}
|
||||
|
||||
if ns::dictionary_objectforkey(data, nsx::string_from_str(PERIPHERALDATA_EVENTSKEY)) == nil
|
||||
{
|
||||
ns::mutabledictionary_setobject_forkey(
|
||||
data,
|
||||
ns::mutabledictionary(),
|
||||
nsx::string_from_str(PERIPHERALDATA_EVENTSKEY),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn delegate_peripheral_diddiscoverservices(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_diddiscoverservices {} {}",
|
||||
cbx::peripheral_debug(peripheral),
|
||||
if error != nil { "error" } else { "" }
|
||||
);
|
||||
if error == nil {
|
||||
let services = cb::peripheral_services(peripheral);
|
||||
for i in 0..ns::array_count(services) {
|
||||
let s = ns::array_objectatindex(services, i);
|
||||
cb::peripheral_discovercharacteristicsforservice(peripheral, s);
|
||||
cb::peripheral_discoverincludedservicesforservice(peripheral, s);
|
||||
}
|
||||
|
||||
// Notify BluetoothDevice::get_gatt_services that discovery was successful.
|
||||
match bmx::peripheralevents(delegate, peripheral) {
|
||||
Ok(events) => ns::mutabledictionary_setobject_forkey(
|
||||
events,
|
||||
wait::now(),
|
||||
nsx::string_from_str(PERIPHERALEVENT_SERVICESDISCOVEREDKEY),
|
||||
),
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn delegate_peripheral_diddiscoverincludedservicesforservice_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
service: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_diddiscoverincludedservicesforservice_error {} {} {}",
|
||||
cbx::peripheral_debug(peripheral),
|
||||
cbx::service_debug(service),
|
||||
if error != nil { "error" } else { "" }
|
||||
);
|
||||
if error == nil {
|
||||
let includes = cb::service_includedservices(service);
|
||||
for i in 0..ns::array_count(includes) {
|
||||
let s = ns::array_objectatindex(includes, i);
|
||||
cb::peripheral_discovercharacteristicsforservice(peripheral, s);
|
||||
}
|
||||
|
||||
// Notify BluetoothGATTService::get_includes that discovery was successful.
|
||||
match bmx::peripheralevents(delegate, peripheral) {
|
||||
Ok(events) => ns::mutabledictionary_setobject_forkey(
|
||||
events,
|
||||
wait::now(),
|
||||
bmx::includedservicesdiscoveredkey(service),
|
||||
),
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn delegate_peripheral_diddiscovercharacteristicsforservice_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
service: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_diddiscovercharacteristicsforservice_error {} {} {}",
|
||||
cbx::peripheral_debug(peripheral),
|
||||
cbx::service_debug(service),
|
||||
if error != nil { "error" } else { "" }
|
||||
);
|
||||
if error == nil {
|
||||
let chars = cb::service_characteristics(service);
|
||||
for i in 0..ns::array_count(chars) {
|
||||
let c = ns::array_objectatindex(chars, i);
|
||||
cb::peripheral_discoverdescriptorsforcharacteristic(peripheral, c);
|
||||
}
|
||||
|
||||
// Notify BluetoothGATTService::get_gatt_characteristics that discovery was successful.
|
||||
match bmx::peripheralevents(delegate, peripheral) {
|
||||
Ok(events) => ns::mutabledictionary_setobject_forkey(
|
||||
events,
|
||||
wait::now(),
|
||||
bmx::characteristicsdiscoveredkey(service),
|
||||
),
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn delegate_peripheral_didupdatevalueforcharacteristic_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
characteristic: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_didupdatevalueforcharacteristic_error {} {} {}",
|
||||
cbx::peripheral_debug(peripheral),
|
||||
cbx::characteristic_debug(characteristic),
|
||||
if error != nil { "error" } else { "" }
|
||||
);
|
||||
if error == nil {
|
||||
// Notify BluetoothGATTCharacteristic::read_value that read was successful.
|
||||
match bmx::peripheralevents(delegate, peripheral) {
|
||||
Ok(events) => ns::mutabledictionary_setobject_forkey(
|
||||
events,
|
||||
wait::now(),
|
||||
bmx::valueupdatedkey(characteristic),
|
||||
),
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn delegate_peripheral_didwritevalueforcharacteristic_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
characteristic: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_didwritevalueforcharacteristic_error {} {} {}",
|
||||
cbx::peripheral_debug(peripheral),
|
||||
cbx::characteristic_debug(characteristic),
|
||||
if error != nil { "error" } else { "" }
|
||||
);
|
||||
if error == nil {
|
||||
// Notify BluetoothGATTCharacteristic::write_value that write was successful.
|
||||
match bmx::peripheralevents(delegate, peripheral) {
|
||||
Ok(events) => ns::mutabledictionary_setobject_forkey(
|
||||
events,
|
||||
wait::now(),
|
||||
bmx::valuewrittenkey(characteristic),
|
||||
),
|
||||
Err(_) => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// extern fn delegate_peripheral_didupdatenotificationstateforcharacteristic_error(_delegate: &mut Object, _cmd: Sel, _peripheral: *mut Object, _characteristic: *mut Object, _error: *mut Object) {
|
||||
// trace!("delegate_peripheral_didupdatenotificationstateforcharacteristic_error");
|
||||
// // TODO: this is where notifications should be handled...
|
||||
// }
|
||||
|
||||
// extern fn delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error(_delegate: &mut Object, _cmd: Sel, _peripheral: *mut Object, _characteristic: *mut Object, _error: *mut Object) {
|
||||
// trace!("delegate_peripheral_diddiscoverdescriptorsforcharacteristic_error");
|
||||
// }
|
||||
|
||||
// extern fn delegate_peripheral_didupdatevaluefordescriptor(_delegate: &mut Object, _cmd: Sel, _peripheral: *mut Object, _descriptor: *mut Object, _error: *mut Object) {
|
||||
// trace!("delegate_peripheral_didupdatevaluefordescriptor");
|
||||
// }
|
||||
|
||||
// extern fn delegate_peripheral_didwritevaluefordescriptor_error(_delegate: &mut Object, _cmd: Sel, _peripheral: *mut Object, _descriptor: *mut Object, _error: *mut Object) {
|
||||
// trace!("delegate_peripheral_didwritevaluefordescriptor_error");
|
||||
// }
|
||||
|
||||
extern "C" fn delegate_peripheral_didreadrssi_error(
|
||||
delegate: &mut Object,
|
||||
_cmd: Sel,
|
||||
peripheral: *mut Object,
|
||||
rssi: *mut Object,
|
||||
error: *mut Object,
|
||||
) {
|
||||
trace!(
|
||||
"delegate_peripheral_didreadrssi_error {}",
|
||||
cbx::peripheral_debug(peripheral)
|
||||
);
|
||||
if error == nil {
|
||||
let peripherals = delegate_peripherals(delegate);
|
||||
let uuid_nsstring = ns::uuid_uuidstring(cb::peer_identifier(peripheral));
|
||||
let data = ns::dictionary_objectforkey(peripherals, uuid_nsstring);
|
||||
if data != nil {
|
||||
ns::mutabledictionary_setobject_forkey(
|
||||
data,
|
||||
rssi,
|
||||
nsx::string_from_str(PERIPHERALDATA_RSSIKEY),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delegate() -> *mut Object {
|
||||
unsafe {
|
||||
let mut delegate: *mut Object = msg_send![delegate_class(), alloc];
|
||||
delegate = msg_send![delegate, init];
|
||||
delegate
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delegate_peripherals(delegate: *mut Object) -> *mut Object {
|
||||
unsafe {
|
||||
let peripherals: *mut Object =
|
||||
*(&mut *delegate).get_ivar::<*mut Object>(DELEGATE_PERIPHERALS_IVAR);
|
||||
peripherals
|
||||
}
|
||||
}
|
||||
|
||||
// "BlurMacPeripheralData" = NSMutableDictionary<NSString*, id>
|
||||
|
||||
pub const PERIPHERALDATA_PERIPHERALKEY: &'static str = "peripheral";
|
||||
pub const PERIPHERALDATA_RSSIKEY: &'static str = "rssi";
|
||||
pub const PERIPHERALDATA_UUIDSKEY: &'static str = "uuids";
|
||||
pub const PERIPHERALDATA_EVENTSKEY: &'static str = "events";
|
||||
|
||||
pub const PERIPHERALEVENT_SERVICESDISCOVEREDKEY: &'static str = "services";
|
||||
pub const PERIPHERALEVENT_INCLUDEDSERVICESDISCOVEREDKEYSUFFIX: &'static str = ":includes";
|
||||
pub const PERIPHERALEVENT_CHARACTERISTICSDISCOVEREDKEYSUFFIX: &'static str = ":characteristics";
|
||||
pub const PERIPHERALEVENT_VALUEUPDATEDKEYSUFFIX: &'static str = ":updated";
|
||||
pub const PERIPHERALEVENT_VALUEWRITTENKEYSUFFIX: &'static str = ":written";
|
||||
}
|
||||
|
||||
pub mod bmx {
|
||||
use super::*;
|
||||
|
||||
pub fn peripheraldata(
|
||||
delegate: *mut Object,
|
||||
peripheral: *mut Object,
|
||||
) -> Result<*mut Object, Box<dyn Error>> {
|
||||
let peripherals = bm::delegate_peripherals(delegate);
|
||||
let data = ns::dictionary_objectforkey(
|
||||
peripherals,
|
||||
ns::uuid_uuidstring(cb::peer_identifier(peripheral)),
|
||||
);
|
||||
if data == nil {
|
||||
warn!("peripheraldata -> NOT FOUND");
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn peripheralevents(
|
||||
delegate: *mut Object,
|
||||
peripheral: *mut Object,
|
||||
) -> Result<*mut Object, Box<dyn Error>> {
|
||||
let data = peripheraldata(delegate, peripheral)?;
|
||||
Ok(ns::dictionary_objectforkey(
|
||||
data,
|
||||
nsx::string_from_str(bm::PERIPHERALDATA_EVENTSKEY),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn includedservicesdiscoveredkey(service: *mut Object) -> *mut Object {
|
||||
suffixedkey(
|
||||
service,
|
||||
bm::PERIPHERALEVENT_INCLUDEDSERVICESDISCOVEREDKEYSUFFIX,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn characteristicsdiscoveredkey(service: *mut Object) -> *mut Object {
|
||||
suffixedkey(
|
||||
service,
|
||||
bm::PERIPHERALEVENT_CHARACTERISTICSDISCOVEREDKEYSUFFIX,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn valueupdatedkey(characteristic: *mut Object) -> *mut Object {
|
||||
suffixedkey(characteristic, bm::PERIPHERALEVENT_VALUEUPDATEDKEYSUFFIX)
|
||||
}
|
||||
|
||||
pub fn valuewrittenkey(characteristic: *mut Object) -> *mut Object {
|
||||
suffixedkey(characteristic, bm::PERIPHERALEVENT_VALUEWRITTENKEYSUFFIX)
|
||||
}
|
||||
|
||||
fn suffixedkey(attribute: *mut Object, suffix: &str) -> *mut Object {
|
||||
let key = format!(
|
||||
"{}{}",
|
||||
cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(attribute)),
|
||||
suffix
|
||||
);
|
||||
nsx::string_from_str(key.as_str())
|
||||
}
|
||||
}
|
280
third_party/blurmac/src/device.rs
vendored
Normal file
280
third_party/blurmac/src/device.rs
vendored
Normal file
|
@ -0,0 +1,280 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use adapter::BluetoothAdapter;
|
||||
use delegate::{bm, bmx};
|
||||
use framework::{cb, nil, ns};
|
||||
use objc::runtime::Object;
|
||||
use utils::{cbx, nsx, wait, NOT_SUPPORTED_ERROR, NO_PERIPHERAL_FOUND};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothDevice {
|
||||
pub(crate) adapter: Arc<BluetoothAdapter>,
|
||||
pub(crate) peripheral: *mut Object,
|
||||
}
|
||||
// TODO: implement std::fmt::Debug and/or std::fmt::Display instead of derive?
|
||||
|
||||
impl BluetoothDevice {
|
||||
pub fn new(adapter: Arc<BluetoothAdapter>, uuid: String) -> BluetoothDevice {
|
||||
trace!("BluetoothDevice::new");
|
||||
// NOTE: It can happen that there is no peripheral for the given UUID, in that case
|
||||
// self.peripheral will be nil and all methods that return a Result will return
|
||||
// Err(Box::from(NO_PERIPHERAL_FOUND)), while others will return some meaningless value.
|
||||
let peripheral = Self::peripheral_by_uuid(adapter.delegate, &uuid);
|
||||
|
||||
if peripheral == nil {
|
||||
warn!("BluetoothDevice::new found no peripheral for UUID {}", uuid);
|
||||
}
|
||||
|
||||
BluetoothDevice {
|
||||
adapter: adapter.clone(),
|
||||
peripheral: peripheral,
|
||||
}
|
||||
}
|
||||
|
||||
fn peripheral_by_uuid(delegate: *mut Object, uuid: &String) -> *mut Object {
|
||||
let peripherals = bm::delegate_peripherals(delegate);
|
||||
let keys = ns::dictionary_allkeys(peripherals);
|
||||
for i in 0..ns::array_count(keys) {
|
||||
let uuid_nsstring = ns::array_objectatindex(keys, i);
|
||||
if nsx::string_to_string(uuid_nsstring) == *uuid {
|
||||
let data = ns::dictionary_objectforkey(peripherals, uuid_nsstring);
|
||||
return ns::dictionary_objectforkey(
|
||||
data,
|
||||
nsx::string_from_str(bm::PERIPHERALDATA_PERIPHERALKEY),
|
||||
);
|
||||
}
|
||||
}
|
||||
nil
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
trace!("BluetoothDevice::get_id -> get_address");
|
||||
self.get_address().unwrap_or(String::new())
|
||||
}
|
||||
|
||||
pub fn get_address(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::get_address");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
// NOTE: There is no better substitute for address than identifier.
|
||||
let uuid_string =
|
||||
nsx::string_to_string(ns::uuid_uuidstring(cb::peer_identifier(self.peripheral)));
|
||||
debug!("BluetoothDevice::get_address -> {}", uuid_string);
|
||||
Ok(uuid_string)
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::get_name");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
let name_nsstring = cb::peripheral_name(self.peripheral);
|
||||
let name = if name_nsstring != nil {
|
||||
nsx::string_to_string(name_nsstring)
|
||||
} else {
|
||||
String::from("")
|
||||
};
|
||||
debug!("BluetoothDevice::get_name -> {}", name);
|
||||
Ok(name)
|
||||
}
|
||||
|
||||
pub fn get_uuids(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::get_uuids");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
let data = bmx::peripheraldata(self.adapter.delegate, self.peripheral)?;
|
||||
let mut v = vec![];
|
||||
let cbuuids_nsarray =
|
||||
ns::dictionary_objectforkey(data, nsx::string_from_str(bm::PERIPHERALDATA_UUIDSKEY));
|
||||
if cbuuids_nsarray != nil {
|
||||
for i in 0..ns::array_count(cbuuids_nsarray) {
|
||||
v.push(cbx::uuid_to_canonical_uuid_string(ns::array_objectatindex(
|
||||
cbuuids_nsarray,
|
||||
i,
|
||||
)));
|
||||
}
|
||||
}
|
||||
debug!("BluetoothDevice::get_uuids -> {:?}", v);
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn connect(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::connect");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
cb::centralmanager_connectperipheral(self.adapter.manager, self.peripheral);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn disconnect(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::disconnect");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
cb::centralmanager_cancelperipheralconnection(self.adapter.manager, self.peripheral);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_connected(&self) -> Result<bool, Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::is_connected");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
let state = cb::peripheral_state(self.peripheral);
|
||||
debug!("BluetoothDevice::is_connected -> {}", state);
|
||||
Ok(state == cb::PERIPHERALSTATE_CONNECTED)
|
||||
}
|
||||
|
||||
pub fn get_gatt_services(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothDevice::get_gatt_services");
|
||||
if self.peripheral == nil {
|
||||
return Err(Box::from(NO_PERIPHERAL_FOUND));
|
||||
}
|
||||
|
||||
let events = bmx::peripheralevents(self.adapter.delegate, self.peripheral)?;
|
||||
let key = nsx::string_from_str(bm::PERIPHERALEVENT_SERVICESDISCOVEREDKEY);
|
||||
wait::wait_or_timeout(|| ns::dictionary_objectforkey(events, key) != nil)?;
|
||||
|
||||
let mut v = vec![];
|
||||
let services = cb::peripheral_services(self.peripheral);
|
||||
for i in 0..ns::array_count(services) {
|
||||
let uuid_string = cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(
|
||||
ns::array_objectatindex(services, i),
|
||||
));
|
||||
v.push(uuid_string);
|
||||
}
|
||||
debug!("BluetoothDevice::get_gatt_services -> {:?}", v);
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
// Not supported
|
||||
|
||||
pub fn get_rssi(&self) -> Result<i16, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_rssi not supported by BlurMac");
|
||||
// TODO: Now available from peripheral data in BluetoothAdapter.
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_tx_power(&self) -> Result<i16, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_tx_power not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_manufacturer_data(&self) -> Result<HashMap<u16, Vec<u8>>, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_manufacturer_data not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_service_data(&self) -> Result<HashMap<String, Vec<u8>>, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_service_data not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_icon(&self) -> Result<String, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_icon not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_class(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_class not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_appearance(&self) -> Result<u16, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_appearance not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_paired(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::is_paired not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_trusted(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::is_trusted not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_blocked(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::is_blocked not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_alias(&self) -> Result<String, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_alias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn set_alias(&self, _value: String) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::set_alias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn is_legacy_pairing(&self) -> Result<bool, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::is_legacy_pairing not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id_source(&self) -> Result<String, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_vendor_id_source not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_vendor_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_vendor_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_product_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_product_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_device_id(&self) -> Result<u32, Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_device_id not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_modalias(&self) -> Result<(String, u32, u32, u32), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::get_modalias not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn connect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::connect_profile not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn disconnect_profile(&self, _uuid: String) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::disconnect_profile not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn pair(&self) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::pair not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn cancel_pairing(&self) -> Result<(), Box<dyn Error>> {
|
||||
warn!("BluetoothDevice::cancel_pairing not supported by BlurMac");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
39
third_party/blurmac/src/discovery_session.rs
vendored
Normal file
39
third_party/blurmac/src/discovery_session.rs
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use adapter::BluetoothAdapter;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothDiscoverySession {
|
||||
// pub(crate) adapter: Arc<BluetoothAdapter>,
|
||||
}
|
||||
|
||||
impl BluetoothDiscoverySession {
|
||||
pub fn create_session(
|
||||
_adapter: Arc<BluetoothAdapter>,
|
||||
) -> Result<BluetoothDiscoverySession, Box<dyn Error>> {
|
||||
trace!("BluetoothDiscoverySession::create_session");
|
||||
Ok(BluetoothDiscoverySession {
|
||||
// adapter: adapter.clone()
|
||||
})
|
||||
}
|
||||
|
||||
pub fn start_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothDiscoverySession::start_discovery");
|
||||
// NOTE: discovery is started by BluetoothAdapter::new to allow devices to pop up
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop_discovery(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothDiscoverySession::stop_discovery");
|
||||
// NOTE: discovery is only stopped when BluetoothAdapter is dropped
|
||||
Ok(())
|
||||
}
|
||||
}
|
490
third_party/blurmac/src/framework.rs
vendored
Normal file
490
third_party/blurmac/src/framework.rs
vendored
Normal file
|
@ -0,0 +1,490 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::os::raw::{c_char, c_int, c_uint};
|
||||
|
||||
use objc::runtime::{Class, Object, BOOL};
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const nil: *mut Object = 0 as *mut Object;
|
||||
|
||||
pub mod ns {
|
||||
use super::*;
|
||||
|
||||
// NSObject
|
||||
|
||||
pub fn object_copy(nsobject: *mut Object) -> *mut Object {
|
||||
unsafe {
|
||||
let copy: *mut Object = msg_send![nsobject, copy];
|
||||
copy
|
||||
}
|
||||
}
|
||||
|
||||
// NSNumber
|
||||
|
||||
pub fn number_withbool(value: BOOL) -> *mut Object {
|
||||
unsafe {
|
||||
let nsnumber: *mut Object =
|
||||
msg_send![Class::get("NSNumber").unwrap(), numberWithBool: value];
|
||||
nsnumber
|
||||
}
|
||||
}
|
||||
|
||||
pub fn number_withunsignedlonglong(value: u64) -> *mut Object {
|
||||
unsafe {
|
||||
let nsnumber: *mut Object = msg_send![
|
||||
Class::get("NSNumber").unwrap(),
|
||||
numberWithUnsignedLongLong: value
|
||||
];
|
||||
nsnumber
|
||||
}
|
||||
}
|
||||
|
||||
pub fn number_unsignedlonglongvalue(nsnumber: *mut Object) -> u64 {
|
||||
unsafe {
|
||||
let value: u64 = msg_send![nsnumber, unsignedLongLongValue];
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
// NSString
|
||||
|
||||
pub fn string(cstring: *const c_char) -> *mut Object /* NSString* */ {
|
||||
unsafe {
|
||||
let nsstring: *mut Object = msg_send![
|
||||
Class::get("NSString").unwrap(),
|
||||
stringWithUTF8String: cstring
|
||||
];
|
||||
nsstring
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_utf8string(nsstring: *mut Object) -> *const c_char {
|
||||
unsafe {
|
||||
let utf8string: *const c_char = msg_send![nsstring, UTF8String];
|
||||
utf8string
|
||||
}
|
||||
}
|
||||
|
||||
// NSArray
|
||||
|
||||
pub fn array_count(nsarray: *mut Object) -> c_uint {
|
||||
unsafe {
|
||||
let count: c_uint = msg_send![nsarray, count];
|
||||
count
|
||||
}
|
||||
}
|
||||
|
||||
pub fn array_objectatindex(nsarray: *mut Object, index: c_uint) -> *mut Object {
|
||||
unsafe {
|
||||
let object: *mut Object = msg_send![nsarray, objectAtIndex: index];
|
||||
object
|
||||
}
|
||||
}
|
||||
|
||||
// NSDictionary
|
||||
|
||||
pub fn dictionary_allkeys(nsdict: *mut Object) -> *mut Object /* NSArray* */ {
|
||||
unsafe {
|
||||
let keys: *mut Object = msg_send![nsdict, allKeys];
|
||||
keys
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dictionary_objectforkey(nsdict: *mut Object, key: *mut Object) -> *mut Object {
|
||||
unsafe {
|
||||
let object: *mut Object = msg_send![nsdict, objectForKey: key];
|
||||
object
|
||||
}
|
||||
}
|
||||
|
||||
// NSMutableDictionary : NSDictionary
|
||||
|
||||
pub fn mutabledictionary() -> *mut Object {
|
||||
unsafe {
|
||||
let nsmutdict: *mut Object =
|
||||
msg_send![Class::get("NSMutableDictionary").unwrap(), dictionaryWithCapacity:0];
|
||||
nsmutdict
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutabledictionary_removeobjectforkey(nsmutdict: *mut Object, key: *mut Object) {
|
||||
unsafe {
|
||||
let () = msg_send![nsmutdict, removeObjectForKey: key];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutabledictionary_setobject_forkey(
|
||||
nsmutdict: *mut Object,
|
||||
object: *mut Object,
|
||||
key: *mut Object,
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![nsmutdict, setObject:object forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
// NSData
|
||||
|
||||
pub fn data(bytes: *const u8, length: c_uint) -> *mut Object /* NSData* */ {
|
||||
unsafe {
|
||||
let data: *mut Object =
|
||||
msg_send![Class::get("NSData").unwrap(), dataWithBytes:bytes length:length];
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_length(nsdata: *mut Object) -> c_uint {
|
||||
unsafe {
|
||||
let length: c_uint = msg_send![nsdata, length];
|
||||
length
|
||||
}
|
||||
}
|
||||
|
||||
pub fn data_bytes(nsdata: *mut Object) -> *const u8 {
|
||||
unsafe {
|
||||
let bytes: *const u8 = msg_send![nsdata, bytes];
|
||||
bytes
|
||||
}
|
||||
}
|
||||
|
||||
// NSUUID
|
||||
|
||||
pub fn uuid_uuidstring(nsuuid: *mut Object) -> *mut Object /* NSString* */ {
|
||||
unsafe {
|
||||
let uuidstring: *mut Object = msg_send![nsuuid, UUIDString];
|
||||
uuidstring
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod io {
|
||||
use super::*;
|
||||
|
||||
#[link(name = "IOBluetooth", kind = "framework")]
|
||||
extern "C" {
|
||||
pub fn IOBluetoothPreferenceGetControllerPowerState() -> c_int;
|
||||
pub fn IOBluetoothPreferenceSetControllerPowerState(state: c_int);
|
||||
|
||||
pub fn IOBluetoothPreferenceGetDiscoverableState() -> c_int;
|
||||
pub fn IOBluetoothPreferenceSetDiscoverableState(state: c_int);
|
||||
}
|
||||
|
||||
// IOBluetoothHostController
|
||||
|
||||
pub fn bluetoothhostcontroller_defaultcontroller() -> *mut Object /* IOBluetoothHostController* */
|
||||
{
|
||||
unsafe {
|
||||
let defaultcontroller: *mut Object = msg_send![
|
||||
Class::get("IOBluetoothHostController").unwrap(),
|
||||
defaultController
|
||||
];
|
||||
defaultcontroller
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bluetoothhostcontroller_nameasstring(iobthc: *mut Object) -> *mut Object /* NSString* */
|
||||
{
|
||||
unsafe {
|
||||
let name: *mut Object = msg_send![iobthc, nameAsString];
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bluetoothhostcontroller_addressasstring(iobthc: *mut Object) -> *mut Object /* NSString* */
|
||||
{
|
||||
unsafe {
|
||||
let address: *mut Object = msg_send![iobthc, addressAsString];
|
||||
address
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bluetoothhostcontroller_classofdevice(iobthc: *mut Object) -> u32 {
|
||||
unsafe {
|
||||
let classofdevice: u32 = msg_send![iobthc, classOfDevice];
|
||||
classofdevice
|
||||
}
|
||||
}
|
||||
|
||||
// IOBluetoothPreference...
|
||||
|
||||
pub fn bluetoothpreferencegetcontrollerpowerstate() -> c_int {
|
||||
unsafe { IOBluetoothPreferenceGetControllerPowerState() }
|
||||
}
|
||||
|
||||
pub fn bluetoothpreferencesetcontrollerpowerstate(state: c_int) {
|
||||
unsafe {
|
||||
IOBluetoothPreferenceSetControllerPowerState(state);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bluetoothpreferencegetdiscoverablestate() -> c_int {
|
||||
unsafe { IOBluetoothPreferenceGetDiscoverableState() }
|
||||
}
|
||||
|
||||
pub fn bluetoothpreferencesetdiscoverablestate(state: c_int) {
|
||||
unsafe {
|
||||
IOBluetoothPreferenceSetDiscoverableState(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod cb {
|
||||
use super::*;
|
||||
|
||||
mod link {
|
||||
use super::*;
|
||||
|
||||
#[link(name = "CoreBluetooth", kind = "framework")]
|
||||
extern "C" {
|
||||
pub static CBAdvertisementDataServiceUUIDsKey: *mut Object;
|
||||
|
||||
pub static CBCentralManagerScanOptionAllowDuplicatesKey: *mut Object;
|
||||
}
|
||||
}
|
||||
|
||||
// CBCentralManager
|
||||
|
||||
pub fn centralmanager(delegate: *mut Object, /*CBCentralManagerDelegate* */) -> *mut Object /*CBCentralManager* */
|
||||
{
|
||||
unsafe {
|
||||
let cbcentralmanager: *mut Object =
|
||||
msg_send![Class::get("CBCentralManager").unwrap(), alloc];
|
||||
let () = msg_send![cbcentralmanager, initWithDelegate:delegate queue:nil];
|
||||
cbcentralmanager
|
||||
}
|
||||
}
|
||||
|
||||
pub fn centralmanager_scanforperipherals_options(
|
||||
cbcentralmanager: *mut Object,
|
||||
options: *mut Object, /* NSDictionary<NSString*,id> */
|
||||
) {
|
||||
unsafe {
|
||||
let () =
|
||||
msg_send![cbcentralmanager, scanForPeripheralsWithServices:nil options:options];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn centralmanager_stopscan(cbcentralmanager: *mut Object) {
|
||||
unsafe {
|
||||
let () = msg_send![cbcentralmanager, stopScan];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn centralmanager_connectperipheral(
|
||||
cbcentralmanager: *mut Object,
|
||||
peripheral: *mut Object, /* CBPeripheral* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbcentralmanager, connectPeripheral:peripheral options:nil];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn centralmanager_cancelperipheralconnection(
|
||||
cbcentralmanager: *mut Object,
|
||||
peripheral: *mut Object, /* CBPeripheral* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbcentralmanager, cancelPeripheralConnection: peripheral];
|
||||
}
|
||||
}
|
||||
|
||||
// CBPeer
|
||||
|
||||
pub fn peer_identifier(cbpeer: *mut Object) -> *mut Object /* NSUUID* */ {
|
||||
unsafe {
|
||||
let identifier: *mut Object = msg_send![cbpeer, identifier];
|
||||
identifier
|
||||
}
|
||||
}
|
||||
|
||||
// CBPeripheral : CBPeer
|
||||
|
||||
pub fn peripheral_name(cbperipheral: *mut Object) -> *mut Object /* NSString* */ {
|
||||
unsafe {
|
||||
let name: *mut Object = msg_send![cbperipheral, name];
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_state(cbperipheral: *mut Object) -> c_int {
|
||||
unsafe {
|
||||
let state: c_int = msg_send![cbperipheral, state];
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_setdelegate(
|
||||
cbperipheral: *mut Object,
|
||||
delegate: *mut Object, /* CBPeripheralDelegate* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, setDelegate: delegate];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_discoverservices(cbperipheral: *mut Object) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, discoverServices: nil];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_discoverincludedservicesforservice(
|
||||
cbperipheral: *mut Object,
|
||||
service: *mut Object, /* CBService* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, discoverIncludedServices:nil forService:service];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_services(cbperipheral: *mut Object) -> *mut Object /* NSArray<CBService*>* */
|
||||
{
|
||||
unsafe {
|
||||
let services: *mut Object = msg_send![cbperipheral, services];
|
||||
services
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_discovercharacteristicsforservice(
|
||||
cbperipheral: *mut Object,
|
||||
service: *mut Object, /* CBService* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, discoverCharacteristics:nil forService:service];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_readvalueforcharacteristic(
|
||||
cbperipheral: *mut Object,
|
||||
characteristic: *mut Object, /* CBCharacteristic* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, readValueForCharacteristic: characteristic];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_writevalue_forcharacteristic(
|
||||
cbperipheral: *mut Object,
|
||||
value: *mut Object, /* NSData* */
|
||||
characteristic: *mut Object, /* CBCharacteristic* */
|
||||
) {
|
||||
unsafe {
|
||||
let () =
|
||||
msg_send![cbperipheral, writeValue:value forCharacteristic:characteristic type:0];
|
||||
// CBCharacteristicWriteWithResponse from CBPeripheral.h
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_setnotifyvalue_forcharacteristic(
|
||||
cbperipheral: *mut Object,
|
||||
value: BOOL,
|
||||
characteristic: *mut Object, /* CBCharacteristic* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![cbperipheral, setNotifyValue:value forCharacteristic:characteristic];
|
||||
}
|
||||
}
|
||||
|
||||
pub fn peripheral_discoverdescriptorsforcharacteristic(
|
||||
cbperipheral: *mut Object,
|
||||
characteristic: *mut Object, /* CBCharacteristic* */
|
||||
) {
|
||||
unsafe {
|
||||
let () = msg_send![
|
||||
cbperipheral,
|
||||
discoverDescriptorsForCharacteristic: characteristic
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// CBPeripheralState = NSInteger from CBPeripheral.h
|
||||
|
||||
pub const PERIPHERALSTATE_CONNECTED: c_int = 2; // CBPeripheralStateConnected
|
||||
|
||||
// CBAttribute
|
||||
|
||||
pub fn attribute_uuid(cbattribute: *mut Object) -> *mut Object /* CBUUID* */ {
|
||||
unsafe {
|
||||
let uuid: *mut Object = msg_send![cbattribute, UUID];
|
||||
uuid
|
||||
}
|
||||
}
|
||||
|
||||
// CBService : CBAttribute
|
||||
|
||||
// pub fn service_isprimary(cbservice: *mut Object) -> BOOL {
|
||||
// unsafe {
|
||||
// let isprimary: BOOL = msg_send![cbservice, isPrimary];
|
||||
// isprimary
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn service_includedservices(cbservice: *mut Object) -> *mut Object /* NSArray<CBService*>* */
|
||||
{
|
||||
unsafe {
|
||||
let includedservices: *mut Object = msg_send![cbservice, includedServices];
|
||||
includedservices
|
||||
}
|
||||
}
|
||||
|
||||
pub fn service_characteristics(cbservice: *mut Object) -> *mut Object /* NSArray<CBCharacteristic*>* */
|
||||
{
|
||||
unsafe {
|
||||
let characteristics: *mut Object = msg_send![cbservice, characteristics];
|
||||
characteristics
|
||||
}
|
||||
}
|
||||
|
||||
// CBCharacteristic : CBAttribute
|
||||
|
||||
pub fn characteristic_isnotifying(cbcharacteristic: *mut Object) -> BOOL {
|
||||
unsafe {
|
||||
let isnotifying: BOOL = msg_send![cbcharacteristic, isNotifying];
|
||||
isnotifying
|
||||
}
|
||||
}
|
||||
|
||||
pub fn characteristic_value(cbcharacteristic: *mut Object) -> *mut Object /* NSData* */ {
|
||||
unsafe {
|
||||
let value: *mut Object = msg_send![cbcharacteristic, value];
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
pub fn characteristic_properties(cbcharacteristic: *mut Object) -> c_uint {
|
||||
unsafe {
|
||||
let properties: c_uint = msg_send![cbcharacteristic, properties];
|
||||
properties
|
||||
}
|
||||
}
|
||||
|
||||
// CBCharacteristicProperties = NSUInteger from CBCharacteristic.h
|
||||
|
||||
pub const CHARACTERISTICPROPERTY_BROADCAST: c_uint = 0x01; // CBCharacteristicPropertyBroadcast
|
||||
pub const CHARACTERISTICPROPERTY_READ: c_uint = 0x02; // CBCharacteristicPropertyRead
|
||||
pub const CHARACTERISTICPROPERTY_WRITEWITHOUTRESPONSE: c_uint = 0x04; // CBCharacteristicPropertyWriteWithoutResponse
|
||||
pub const CHARACTERISTICPROPERTY_WRITE: c_uint = 0x08; // CBCharacteristicPropertyWrite
|
||||
pub const CHARACTERISTICPROPERTY_NOTIFY: c_uint = 0x10; // CBCharacteristicPropertyNotify
|
||||
pub const CHARACTERISTICPROPERTY_INDICATE: c_uint = 0x20; // CBCharacteristicPropertyIndicate
|
||||
pub const CHARACTERISTICPROPERTY_AUTHENTICATEDSIGNEDWRITES: c_uint = 0x40; // CBCharacteristicPropertyAuthenticatedSignedWrites
|
||||
|
||||
// CBUUID
|
||||
|
||||
pub fn uuid_uuidstring(cbuuid: *mut Object) -> *mut Object /* NSString* */ {
|
||||
unsafe {
|
||||
let uuidstring: *mut Object = msg_send![cbuuid, UUIDString];
|
||||
uuidstring
|
||||
}
|
||||
}
|
||||
|
||||
// CBCentralManagerScanOption...Key
|
||||
|
||||
// CBAdvertisementData...Key
|
||||
pub use self::link::CBAdvertisementDataServiceUUIDsKey as ADVERTISEMENTDATASERVICEUUIDSKEY;
|
||||
pub use self::link::CBCentralManagerScanOptionAllowDuplicatesKey as CENTRALMANAGERSCANOPTIONALLOWDUPLICATESKEY;
|
||||
}
|
225
third_party/blurmac/src/gatt_characteristic.rs
vendored
Normal file
225
third_party/blurmac/src/gatt_characteristic.rs
vendored
Normal file
|
@ -0,0 +1,225 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::os::raw::c_uint;
|
||||
use std::slice;
|
||||
use std::sync::Arc;
|
||||
|
||||
use delegate::bmx;
|
||||
use framework::{cb, nil, ns};
|
||||
use gatt_service::BluetoothGATTService;
|
||||
use objc::runtime::{Object, NO, YES};
|
||||
use utils::{cbx, wait, NOT_SUPPORTED_ERROR, NO_CHARACTERISTIC_FOUND};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTCharacteristic {
|
||||
pub(crate) service: Arc<BluetoothGATTService>,
|
||||
pub(crate) characteristic: *mut Object,
|
||||
}
|
||||
// TODO: implement std::fmt::Debug and/or std::fmt::Display instead of derive?
|
||||
|
||||
impl BluetoothGATTCharacteristic {
|
||||
pub fn new(service: Arc<BluetoothGATTService>, uuid: String) -> BluetoothGATTCharacteristic {
|
||||
// NOTE: It can happen that there is no characteristic for the given UUID, in that case
|
||||
// self.characteristic will be nil and all methods that return a Result will return
|
||||
// Err(Box::from(NO_CHARACTERISTIC_FOUND)), while others will return some meaningless value.
|
||||
let characteristic = Self::characteristic_by_uuid(service.service, &uuid);
|
||||
|
||||
if characteristic == nil {
|
||||
warn!(
|
||||
"BluetoothGATTCharacteristic::new found no characteristic for UUID {}",
|
||||
uuid
|
||||
);
|
||||
}
|
||||
|
||||
BluetoothGATTCharacteristic {
|
||||
service: service.clone(),
|
||||
characteristic: characteristic,
|
||||
}
|
||||
}
|
||||
|
||||
fn characteristic_by_uuid(service: *mut Object, uuid: &String) -> *mut Object {
|
||||
if service != nil {
|
||||
let chars = cb::service_characteristics(service);
|
||||
for i in 0..ns::array_count(chars) {
|
||||
let c = ns::array_objectatindex(chars, i);
|
||||
if cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(c)) == *uuid {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
nil
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
trace!("BluetoothGATTCharacteristic::get_id");
|
||||
self.get_uuid().unwrap_or(String::new())
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::get_uuid");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let uuid_string =
|
||||
cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(self.characteristic));
|
||||
debug!("BluetoothGATTCharacteristic::get_uuid -> {}", uuid_string);
|
||||
Ok(uuid_string)
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::get_value");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let value = cb::characteristic_value(self.characteristic);
|
||||
let length = ns::data_length(value);
|
||||
if length == 0 {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
let bytes = ns::data_bytes(value);
|
||||
let v = unsafe { slice::from_raw_parts(bytes, length as usize).to_vec() };
|
||||
debug!("BluetoothGATTCharacteristic::get_value -> {:?}", v);
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::read_value");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let events = bmx::peripheralevents(
|
||||
self.service.device.adapter.delegate,
|
||||
self.service.device.peripheral,
|
||||
)?;
|
||||
let key = bmx::valueupdatedkey(self.characteristic);
|
||||
let t = wait::get_timestamp();
|
||||
|
||||
cb::peripheral_readvalueforcharacteristic(
|
||||
self.service.device.peripheral,
|
||||
self.characteristic,
|
||||
);
|
||||
|
||||
wait::wait_or_timeout(|| {
|
||||
let nsnumber = ns::dictionary_objectforkey(events, key);
|
||||
(nsnumber != nil) && (ns::number_unsignedlonglongvalue(nsnumber) >= t)
|
||||
})?;
|
||||
|
||||
self.get_value()
|
||||
}
|
||||
|
||||
pub fn write_value(&self, values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::write_value");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let events = bmx::peripheralevents(
|
||||
self.service.device.adapter.delegate,
|
||||
self.service.device.peripheral,
|
||||
)?;
|
||||
let key = bmx::valuewrittenkey(self.characteristic);
|
||||
let t = wait::get_timestamp();
|
||||
|
||||
cb::peripheral_writevalue_forcharacteristic(
|
||||
self.service.device.peripheral,
|
||||
ns::data(values.as_ptr(), values.len() as c_uint),
|
||||
self.characteristic,
|
||||
);
|
||||
|
||||
wait::wait_or_timeout(|| {
|
||||
let nsnumber = ns::dictionary_objectforkey(events, key);
|
||||
(nsnumber != nil) && (ns::number_unsignedlonglongvalue(nsnumber) >= t)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_notifying(&self) -> Result<bool, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::is_notifying");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let notifying = cb::characteristic_isnotifying(self.characteristic);
|
||||
debug!("BluetoothGATTCharacteristic::is_notifying -> {}", notifying);
|
||||
Ok(notifying != NO)
|
||||
}
|
||||
|
||||
pub fn start_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::start_notify");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
cb::peripheral_setnotifyvalue_forcharacteristic(
|
||||
self.service.device.peripheral,
|
||||
YES,
|
||||
self.characteristic,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop_notify(&self) -> Result<(), Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::stop_notify");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
cb::peripheral_setnotifyvalue_forcharacteristic(
|
||||
self.service.device.peripheral,
|
||||
NO,
|
||||
self.characteristic,
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_gatt_descriptors(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
warn!("BluetoothGATTCharacteristic::get_gatt_descriptors");
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTCharacteristic::get_flags");
|
||||
if self.characteristic == nil {
|
||||
return Err(Box::from(NO_CHARACTERISTIC_FOUND));
|
||||
}
|
||||
|
||||
let flags = cb::characteristic_properties(self.characteristic);
|
||||
// NOTE: It is not documented anywhere what strings to return. Strings below were
|
||||
// reverse-engineered from the sources of blurdroid.
|
||||
let mut v = vec![];
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_BROADCAST) != 0 {
|
||||
v.push(String::from("broadcast"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_READ) != 0 {
|
||||
v.push(String::from("read"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_WRITEWITHOUTRESPONSE) != 0 {
|
||||
v.push(String::from("write-without-response"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_WRITE) != 0 {
|
||||
v.push(String::from("write"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_NOTIFY) != 0 {
|
||||
v.push(String::from("notify"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_INDICATE) != 0 {
|
||||
v.push(String::from("indicate"));
|
||||
}
|
||||
if (flags & cb::CHARACTERISTICPROPERTY_AUTHENTICATEDSIGNEDWRITES) != 0 {
|
||||
v.push(String::from("authenticated-signed-writes"));
|
||||
}
|
||||
debug!("BluetoothGATTCharacteristic::get_flags -> {:?}", v);
|
||||
Ok(v)
|
||||
}
|
||||
}
|
43
third_party/blurmac/src/gatt_descriptor.rs
vendored
Normal file
43
third_party/blurmac/src/gatt_descriptor.rs
vendored
Normal file
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
|
||||
use utils::NOT_SUPPORTED_ERROR;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTDescriptor {}
|
||||
|
||||
impl BluetoothGATTDescriptor {
|
||||
pub fn new(_descriptor: String) -> BluetoothGATTDescriptor {
|
||||
BluetoothGATTDescriptor {}
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
String::new()
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn get_flags(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn read_value(&self) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
|
||||
pub fn write_value(&self, _values: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||
Err(Box::from(NOT_SUPPORTED_ERROR))
|
||||
}
|
||||
}
|
128
third_party/blurmac/src/gatt_service.rs
vendored
Normal file
128
third_party/blurmac/src/gatt_service.rs
vendored
Normal file
|
@ -0,0 +1,128 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
use delegate::bmx;
|
||||
use device::BluetoothDevice;
|
||||
use framework::{cb, nil, ns};
|
||||
use objc::runtime::Object;
|
||||
use utils::{cbx, wait, NO_SERVICE_FOUND};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct BluetoothGATTService {
|
||||
pub(crate) device: Arc<BluetoothDevice>,
|
||||
pub(crate) service: *mut Object,
|
||||
}
|
||||
// TODO: implement std::fmt::Debug and/or std::fmt::Display instead of derive?
|
||||
|
||||
impl BluetoothGATTService {
|
||||
pub fn new(device: Arc<BluetoothDevice>, uuid: String) -> BluetoothGATTService {
|
||||
trace!("BluetoothGATTService::new");
|
||||
// NOTE: It can happen that there is no service for the given UUID, in that case
|
||||
// self.service will be nil and all methods that return a Result will return
|
||||
// Err(Box::from(NO_SERVICE_FOUND)), while others will return some meaningless value.
|
||||
let service = Self::service_by_uuid(device.peripheral, &uuid);
|
||||
|
||||
if service == nil {
|
||||
warn!(
|
||||
"BluetoothGATTService::new found no service for UUID {}",
|
||||
uuid
|
||||
);
|
||||
}
|
||||
|
||||
BluetoothGATTService {
|
||||
device: device.clone(),
|
||||
service: service,
|
||||
}
|
||||
}
|
||||
|
||||
fn service_by_uuid(peripheral: *mut Object, uuid: &String) -> *mut Object {
|
||||
if peripheral != nil {
|
||||
// TODO: This function will most probably not find included services. Make it recursively
|
||||
// descend into included services if first loop did not find what it was looking for.
|
||||
let services = cb::peripheral_services(peripheral);
|
||||
for i in 0..ns::array_count(services) {
|
||||
let s = ns::array_objectatindex(services, i);
|
||||
if cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(s)) == *uuid {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
nil
|
||||
}
|
||||
|
||||
pub fn get_id(&self) -> String {
|
||||
trace!("BluetoothGATTService::get_id");
|
||||
self.get_uuid().unwrap_or(String::new())
|
||||
}
|
||||
|
||||
pub fn get_uuid(&self) -> Result<String, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTService::get_uuid");
|
||||
if self.service == nil {
|
||||
return Err(Box::from(NO_SERVICE_FOUND));
|
||||
}
|
||||
|
||||
let uuid_string = cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(self.service));
|
||||
debug!("BluetoothGATTService::get_uuid -> {}", uuid_string);
|
||||
Ok(uuid_string)
|
||||
}
|
||||
|
||||
pub fn is_primary(&self) -> Result<bool, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTService::is_primary");
|
||||
if self.service == nil {
|
||||
return Err(Box::from(NO_SERVICE_FOUND));
|
||||
}
|
||||
|
||||
// let primary = cb::service_isprimary(self.service);
|
||||
// debug!("BluetoothGATTService::is_primary -> {}", primary);
|
||||
// Ok(primary != NO)
|
||||
// FIXME: dirty hack. no idea why [CBService isPrimary] returns NO for a primary service.
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn get_includes(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTService::get_includes");
|
||||
if self.service == nil {
|
||||
return Err(Box::from(NO_SERVICE_FOUND));
|
||||
}
|
||||
|
||||
let events = bmx::peripheralevents(self.device.adapter.delegate, self.device.peripheral)?;
|
||||
let key = bmx::includedservicesdiscoveredkey(self.service);
|
||||
wait::wait_or_timeout(|| ns::dictionary_objectforkey(events, key) != nil)?;
|
||||
|
||||
let mut v = vec![];
|
||||
let includes = cb::service_includedservices(self.service);
|
||||
for i in 0..ns::array_count(includes) {
|
||||
v.push(cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(
|
||||
ns::array_objectatindex(includes, i),
|
||||
)));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
|
||||
pub fn get_gatt_characteristics(&self) -> Result<Vec<String>, Box<dyn Error>> {
|
||||
trace!("BluetoothGATTService::get_gatt_characteristics");
|
||||
if self.service == nil {
|
||||
return Err(Box::from(NO_SERVICE_FOUND));
|
||||
}
|
||||
|
||||
let events = bmx::peripheralevents(self.device.adapter.delegate, self.device.peripheral)?;
|
||||
let key = bmx::characteristicsdiscoveredkey(self.service);
|
||||
wait::wait_or_timeout(|| ns::dictionary_objectforkey(events, key) != nil)?;
|
||||
|
||||
let mut v = vec![];
|
||||
let chars = cb::service_characteristics(self.service);
|
||||
for i in 0..ns::array_count(chars) {
|
||||
v.push(cbx::uuid_to_canonical_uuid_string(cb::attribute_uuid(
|
||||
ns::array_objectatindex(chars, i),
|
||||
)));
|
||||
}
|
||||
Ok(v)
|
||||
}
|
||||
}
|
28
third_party/blurmac/src/lib.rs
vendored
Normal file
28
third_party/blurmac/src/lib.rs
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate objc;
|
||||
|
||||
mod adapter;
|
||||
mod delegate;
|
||||
mod device;
|
||||
mod discovery_session;
|
||||
mod framework;
|
||||
mod gatt_characteristic;
|
||||
mod gatt_descriptor;
|
||||
mod gatt_service;
|
||||
mod utils;
|
||||
|
||||
pub use adapter::BluetoothAdapter;
|
||||
pub use device::BluetoothDevice;
|
||||
pub use discovery_session::BluetoothDiscoverySession;
|
||||
pub use gatt_characteristic::BluetoothGATTCharacteristic;
|
||||
pub use gatt_descriptor::BluetoothGATTDescriptor;
|
||||
pub use gatt_service::BluetoothGATTService;
|
122
third_party/blurmac/src/utils.rs
vendored
Normal file
122
third_party/blurmac/src/utils.rs
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) 2017 Akos Kiss.
|
||||
//
|
||||
// Licensed under the BSD 3-Clause License
|
||||
// <LICENSE.md or https://opensource.org/licenses/BSD-3-Clause>.
|
||||
// This file may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::error::Error;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::{thread, time};
|
||||
|
||||
use framework::{cb, nil, ns};
|
||||
use objc::runtime::Object;
|
||||
|
||||
pub const NOT_SUPPORTED_ERROR: &'static str = "Error! Not supported by blurmac!";
|
||||
pub const NO_PERIPHERAL_FOUND: &'static str = "Error! No peripheral found!";
|
||||
pub const NO_SERVICE_FOUND: &'static str = "Error! No service found!";
|
||||
pub const NO_CHARACTERISTIC_FOUND: &'static str = "Error! No characteristic found!";
|
||||
|
||||
pub mod nsx {
|
||||
use super::*;
|
||||
|
||||
pub fn string_to_string(nsstring: *mut Object) -> String {
|
||||
if nsstring == nil {
|
||||
return String::from("nil");
|
||||
}
|
||||
unsafe {
|
||||
String::from(
|
||||
CStr::from_ptr(ns::string_utf8string(nsstring))
|
||||
.to_str()
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn string_from_str(string: &str) -> *mut Object {
|
||||
let cstring = CString::new(string).unwrap();
|
||||
ns::string(cstring.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
pub mod cbx {
|
||||
use super::*;
|
||||
|
||||
pub fn uuid_to_canonical_uuid_string(cbuuid: *mut Object) -> String {
|
||||
// NOTE: CoreBluetooth tends to return uppercase UUID strings, and only 4 character long if the
|
||||
// UUID is short (16 bits). However, WebBluetooth mandates lowercase UUID strings. And Servo
|
||||
// seems to compare strings, not the binary representation.
|
||||
let uuid = nsx::string_to_string(cb::uuid_uuidstring(cbuuid));
|
||||
let long = if uuid.len() == 4 {
|
||||
format!("0000{}-0000-1000-8000-00805f9b34fb", uuid)
|
||||
} else {
|
||||
uuid
|
||||
};
|
||||
long.to_lowercase()
|
||||
}
|
||||
|
||||
pub fn peripheral_debug(peripheral: *mut Object) -> String {
|
||||
if peripheral == nil {
|
||||
return String::from("nil");
|
||||
}
|
||||
let name = cb::peripheral_name(peripheral);
|
||||
let uuid = ns::uuid_uuidstring(cb::peer_identifier(peripheral));
|
||||
if name != nil {
|
||||
format!(
|
||||
"CBPeripheral({}, {})",
|
||||
nsx::string_to_string(name),
|
||||
nsx::string_to_string(uuid)
|
||||
)
|
||||
} else {
|
||||
format!("CBPeripheral({})", nsx::string_to_string(uuid))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn service_debug(service: *mut Object) -> String {
|
||||
if service == nil {
|
||||
return String::from("nil");
|
||||
}
|
||||
let uuid = cb::uuid_uuidstring(cb::attribute_uuid(service));
|
||||
format!("CBService({})", nsx::string_to_string(uuid))
|
||||
}
|
||||
|
||||
pub fn characteristic_debug(characteristic: *mut Object) -> String {
|
||||
if characteristic == nil {
|
||||
return String::from("nil");
|
||||
}
|
||||
let uuid = cb::uuid_uuidstring(cb::attribute_uuid(characteristic));
|
||||
format!("CBCharacteristic({})", nsx::string_to_string(uuid))
|
||||
}
|
||||
}
|
||||
|
||||
pub mod wait {
|
||||
use super::*;
|
||||
|
||||
pub type Timestamp = u64;
|
||||
|
||||
static TIMESTAMP: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
pub fn get_timestamp() -> Timestamp {
|
||||
TIMESTAMP.fetch_add(1, Ordering::SeqCst) as u64
|
||||
}
|
||||
|
||||
pub fn now() -> *mut Object {
|
||||
ns::number_withunsignedlonglong(get_timestamp())
|
||||
}
|
||||
|
||||
pub fn wait_or_timeout<F>(mut f: F) -> Result<(), Box<dyn Error>>
|
||||
where
|
||||
F: FnMut() -> bool,
|
||||
{
|
||||
let now = time::Instant::now();
|
||||
|
||||
while !f() {
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
if now.elapsed().as_secs() > 30 {
|
||||
return Err(Box::from("timeout"));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue