mirror of
https://github.com/servo/servo.git
synced 2025-08-05 05:30:08 +01:00
Auto merge of #10632 - szeged:bluetooth-ipc, r=jdm
WebBluetooth impementation Update the current WebBluetooth implementation. <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/10632) <!-- Reviewable:end -->
This commit is contained in:
commit
944a8dc25a
36 changed files with 2178 additions and 125 deletions
|
@ -34,6 +34,7 @@ matrix:
|
||||||
- python-virtualenv
|
- python-virtualenv
|
||||||
- xorg-dev
|
- xorg-dev
|
||||||
- ccache
|
- ccache
|
||||||
|
- libdbus-glib-1-dev
|
||||||
|
|
||||||
branches:
|
branches:
|
||||||
only:
|
only:
|
||||||
|
|
|
@ -36,6 +36,7 @@ use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationD
|
||||||
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
||||||
use msg::constellation_msg::{self, ConstellationChan, PanicMsg};
|
use msg::constellation_msg::{self, ConstellationChan, PanicMsg};
|
||||||
use msg::webdriver_msg;
|
use msg::webdriver_msg;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::storage_thread::{StorageThread, StorageThreadMsg};
|
use net_traits::storage_thread::{StorageThread, StorageThreadMsg};
|
||||||
use net_traits::{self, ResourceThread};
|
use net_traits::{self, ResourceThread};
|
||||||
|
@ -123,6 +124,9 @@ pub struct Constellation<LTF, STF> {
|
||||||
/// A channel through which messages can be sent to the developer tools.
|
/// A channel through which messages can be sent to the developer tools.
|
||||||
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||||
|
|
||||||
|
/// A channel through which messages can be sent to the bluetooth thread.
|
||||||
|
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
|
|
||||||
/// A channel through which messages can be sent to the storage thread.
|
/// A channel through which messages can be sent to the storage thread.
|
||||||
storage_thread: StorageThread,
|
storage_thread: StorageThread,
|
||||||
|
|
||||||
|
@ -197,6 +201,8 @@ pub struct InitialConstellationState {
|
||||||
pub compositor_proxy: Box<CompositorProxy + Send>,
|
pub compositor_proxy: Box<CompositorProxy + Send>,
|
||||||
/// A channel to the developer tools, if applicable.
|
/// A channel to the developer tools, if applicable.
|
||||||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||||
|
/// A channel to the bluetooth thread.
|
||||||
|
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
/// A channel to the image cache thread.
|
/// A channel to the image cache thread.
|
||||||
pub image_cache_thread: ImageCacheThread,
|
pub image_cache_thread: ImageCacheThread,
|
||||||
/// A channel to the font cache thread.
|
/// A channel to the font cache thread.
|
||||||
|
@ -338,6 +344,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
panic_receiver: panic_receiver,
|
panic_receiver: panic_receiver,
|
||||||
compositor_proxy: state.compositor_proxy,
|
compositor_proxy: state.compositor_proxy,
|
||||||
devtools_chan: state.devtools_chan,
|
devtools_chan: state.devtools_chan,
|
||||||
|
bluetooth_thread: state.bluetooth_thread,
|
||||||
resource_thread: state.resource_thread,
|
resource_thread: state.resource_thread,
|
||||||
image_cache_thread: state.image_cache_thread,
|
image_cache_thread: state.image_cache_thread,
|
||||||
font_cache_thread: state.font_cache_thread,
|
font_cache_thread: state.font_cache_thread,
|
||||||
|
@ -424,6 +431,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
scheduler_chan: self.scheduler_chan.clone(),
|
scheduler_chan: self.scheduler_chan.clone(),
|
||||||
compositor_proxy: self.compositor_proxy.clone_compositor_proxy(),
|
compositor_proxy: self.compositor_proxy.clone_compositor_proxy(),
|
||||||
devtools_chan: self.devtools_chan.clone(),
|
devtools_chan: self.devtools_chan.clone(),
|
||||||
|
bluetooth_thread: self.bluetooth_thread.clone(),
|
||||||
image_cache_thread: self.image_cache_thread.clone(),
|
image_cache_thread: self.image_cache_thread.clone(),
|
||||||
font_cache_thread: self.font_cache_thread.clone(),
|
font_cache_thread: self.font_cache_thread.clone(),
|
||||||
resource_thread: self.resource_thread.clone(),
|
resource_thread: self.resource_thread.clone(),
|
||||||
|
@ -840,6 +848,9 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
||||||
if let Err(e) = self.storage_thread.send(StorageThreadMsg::Exit) {
|
if let Err(e) = self.storage_thread.send(StorageThreadMsg::Exit) {
|
||||||
warn!("Exit storage thread failed ({})", e);
|
warn!("Exit storage thread failed ({})", e);
|
||||||
}
|
}
|
||||||
|
if let Err(e) = self.bluetooth_thread.send(BluetoothMethodMsg::Exit) {
|
||||||
|
warn!("Exit bluetooth thread failed ({})", e);
|
||||||
|
}
|
||||||
self.font_cache_thread.exit();
|
self.font_cache_thread.exit();
|
||||||
self.compositor_proxy.send(ToCompositorMsg::ShutdownComplete);
|
self.compositor_proxy.send(ToCompositorMsg::ShutdownComplete);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ use msg::constellation_msg::{ConstellationChan, PanicMsg, FrameId, PipelineId, S
|
||||||
use msg::constellation_msg::{LoadData, WindowSizeData};
|
use msg::constellation_msg::{LoadData, WindowSizeData};
|
||||||
use msg::constellation_msg::{PipelineNamespaceId};
|
use msg::constellation_msg::{PipelineNamespaceId};
|
||||||
use net_traits::ResourceThread;
|
use net_traits::ResourceThread;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::storage_thread::StorageThread;
|
use net_traits::storage_thread::StorageThread;
|
||||||
use profile_traits::mem as profile_mem;
|
use profile_traits::mem as profile_mem;
|
||||||
|
@ -92,6 +93,8 @@ pub struct InitialPipelineState {
|
||||||
pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||||
/// A channel to the developer tools, if applicable.
|
/// A channel to the developer tools, if applicable.
|
||||||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||||
|
/// A channel to the bluetooth thread.
|
||||||
|
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
/// A channel to the image cache thread.
|
/// A channel to the image cache thread.
|
||||||
pub image_cache_thread: ImageCacheThread,
|
pub image_cache_thread: ImageCacheThread,
|
||||||
/// A channel to the font cache thread.
|
/// A channel to the font cache thread.
|
||||||
|
@ -214,6 +217,7 @@ impl Pipeline {
|
||||||
constellation_chan: state.constellation_chan,
|
constellation_chan: state.constellation_chan,
|
||||||
scheduler_chan: state.scheduler_chan,
|
scheduler_chan: state.scheduler_chan,
|
||||||
devtools_chan: script_to_devtools_chan,
|
devtools_chan: script_to_devtools_chan,
|
||||||
|
bluetooth_thread: state.bluetooth_thread,
|
||||||
image_cache_thread: state.image_cache_thread,
|
image_cache_thread: state.image_cache_thread,
|
||||||
font_cache_thread: state.font_cache_thread.clone(),
|
font_cache_thread: state.font_cache_thread.clone(),
|
||||||
resource_thread: state.resource_thread,
|
resource_thread: state.resource_thread,
|
||||||
|
@ -390,6 +394,7 @@ pub struct UnprivilegedPipelineContent {
|
||||||
scheduler_chan: IpcSender<TimerEventRequest>,
|
scheduler_chan: IpcSender<TimerEventRequest>,
|
||||||
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||||
script_to_compositor_chan: IpcSender<ScriptToCompositorMsg>,
|
script_to_compositor_chan: IpcSender<ScriptToCompositorMsg>,
|
||||||
|
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
image_cache_thread: ImageCacheThread,
|
image_cache_thread: ImageCacheThread,
|
||||||
font_cache_thread: FontCacheThread,
|
font_cache_thread: FontCacheThread,
|
||||||
resource_thread: ResourceThread,
|
resource_thread: ResourceThread,
|
||||||
|
@ -430,6 +435,7 @@ impl UnprivilegedPipelineContent {
|
||||||
layout_to_constellation_chan: self.layout_to_constellation_chan.clone(),
|
layout_to_constellation_chan: self.layout_to_constellation_chan.clone(),
|
||||||
scheduler_chan: self.scheduler_chan.clone(),
|
scheduler_chan: self.scheduler_chan.clone(),
|
||||||
panic_chan: self.panic_chan.clone(),
|
panic_chan: self.panic_chan.clone(),
|
||||||
|
bluetooth_thread: self.bluetooth_thread.clone(),
|
||||||
resource_thread: self.resource_thread,
|
resource_thread: self.resource_thread,
|
||||||
storage_thread: self.storage_thread.clone(),
|
storage_thread: self.storage_thread.clone(),
|
||||||
image_cache_thread: self.image_cache_thread.clone(),
|
image_cache_thread: self.image_cache_thread.clone(),
|
||||||
|
|
|
@ -17,6 +17,8 @@ plugins = {path = "../plugins"}
|
||||||
msg = {path = "../msg"}
|
msg = {path = "../msg"}
|
||||||
ipc-channel = {git = "https://github.com/servo/ipc-channel"}
|
ipc-channel = {git = "https://github.com/servo/ipc-channel"}
|
||||||
webrender_traits = {git = "https://github.com/servo/webrender_traits"}
|
webrender_traits = {git = "https://github.com/servo/webrender_traits"}
|
||||||
|
device = {git = "https://github.com/servo/devices"}
|
||||||
|
bitflags = "0.6.0"
|
||||||
cookie = { version = "0.2.4", features = [ "serialize-rustc" ] }
|
cookie = { version = "0.2.4", features = [ "serialize-rustc" ] }
|
||||||
flate2 = "0.2.0"
|
flate2 = "0.2.0"
|
||||||
hyper = { version = "0.9", features = [ "serde-serialization" ] }
|
hyper = { version = "0.9", features = [ "serde-serialization" ] }
|
||||||
|
|
649
components/net/bluetooth_thread.rs
Normal file
649
components/net/bluetooth_thread.rs
Normal file
|
@ -0,0 +1,649 @@
|
||||||
|
/* 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 device::bluetooth::BluetoothAdapter;
|
||||||
|
use device::bluetooth::BluetoothDevice;
|
||||||
|
use device::bluetooth::BluetoothGATTCharacteristic;
|
||||||
|
use device::bluetooth::BluetoothGATTDescriptor;
|
||||||
|
use device::bluetooth::BluetoothGATTService;
|
||||||
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
|
use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions};
|
||||||
|
use net_traits::bluetooth_thread::{BluetoothCharacteristicMsg, BluetoothCharacteristicsMsg};
|
||||||
|
use net_traits::bluetooth_thread::{BluetoothDescriptorMsg, BluetoothDescriptorsMsg};
|
||||||
|
use net_traits::bluetooth_thread::{BluetoothDeviceMsg, BluetoothMethodMsg};
|
||||||
|
use net_traits::bluetooth_thread::{BluetoothResult, BluetoothServiceMsg, BluetoothServicesMsg};
|
||||||
|
use std::borrow::ToOwned;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::string::String;
|
||||||
|
use util::thread::spawn_named;
|
||||||
|
|
||||||
|
const ADAPTER_ERROR: &'static str = "No adapter found";
|
||||||
|
const DEVICE_ERROR: &'static str = "No device found";
|
||||||
|
const DEVICE_MATCH_ERROR: &'static str = "No device found, that matches the given options";
|
||||||
|
const PRIMARY_SERVICE_ERROR: &'static str = "No primary service found";
|
||||||
|
const CHARACTERISTIC_ERROR: &'static str = "No characteristic found";
|
||||||
|
const DESCRIPTOR_ERROR: &'static str = "No descriptor found";
|
||||||
|
const VALUE_ERROR: &'static str = "No characteristic or descriptor found with that id";
|
||||||
|
|
||||||
|
bitflags! {
|
||||||
|
flags Flags: u32 {
|
||||||
|
const BROADCAST = 0b000000001,
|
||||||
|
const READ = 0b000000010,
|
||||||
|
const WRITE_WITHOUT_RESPONSE = 0b000000100,
|
||||||
|
const WRITE = 0b000001000,
|
||||||
|
const NOTIFY = 0b000010000,
|
||||||
|
const INDICATE = 0b000100000,
|
||||||
|
const AUTHENTICATED_SIGNED_WRITES = 0b001000000,
|
||||||
|
const RELIABLE_WRITE = 0b010000000,
|
||||||
|
const WRITABLE_AUXILIARIES = 0b100000000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! return_if_cached(
|
||||||
|
($cache:expr, $key:expr) => (
|
||||||
|
if $cache.contains_key($key) {
|
||||||
|
return $cache.get($key);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
pub trait BluetoothThreadFactory {
|
||||||
|
fn new() -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BluetoothThreadFactory for IpcSender<BluetoothMethodMsg> {
|
||||||
|
fn new() -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
let adapter = BluetoothAdapter::init().ok();
|
||||||
|
spawn_named("BluetoothThread".to_owned(), move || {
|
||||||
|
BluetoothManager::new(receiver, adapter).start();
|
||||||
|
});
|
||||||
|
sender
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_filter(device: &BluetoothDevice, filter: &BluetoothScanfilter) -> bool {
|
||||||
|
if filter.is_empty_or_invalid() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !filter.get_name().is_empty() {
|
||||||
|
if device.get_name().ok() != Some(filter.get_name().to_string()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !filter.get_name_prefix().is_empty() {
|
||||||
|
if let Ok(device_name) = device.get_name() {
|
||||||
|
if !device_name.starts_with(filter.get_name_prefix()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !filter.get_services().is_empty() {
|
||||||
|
if let Ok(device_uuids) = device.get_uuids() {
|
||||||
|
for service in filter.get_services() {
|
||||||
|
if device_uuids.iter().find(|x| x == &service).is_none() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_filters(device: &BluetoothDevice, filters: &BluetoothScanfilterSequence) -> bool {
|
||||||
|
if filters.has_empty_or_invalid_filter() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filters.iter().any(|f| matches_filter(device, f))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct BluetoothManager {
|
||||||
|
receiver: IpcReceiver<BluetoothMethodMsg>,
|
||||||
|
adapter: Option<BluetoothAdapter>,
|
||||||
|
service_to_device: HashMap<String, String>,
|
||||||
|
characteristic_to_service: HashMap<String, String>,
|
||||||
|
descriptor_to_characteristic: HashMap<String, String>,
|
||||||
|
cached_devices: HashMap<String, BluetoothDevice>,
|
||||||
|
cached_services: HashMap<String, BluetoothGATTService>,
|
||||||
|
cached_characteristics: HashMap<String, BluetoothGATTCharacteristic>,
|
||||||
|
cached_descriptors: HashMap<String, BluetoothGATTDescriptor>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BluetoothManager {
|
||||||
|
pub fn new (receiver: IpcReceiver<BluetoothMethodMsg>, adapter: Option<BluetoothAdapter>) -> BluetoothManager {
|
||||||
|
BluetoothManager {
|
||||||
|
receiver: receiver,
|
||||||
|
adapter: adapter,
|
||||||
|
service_to_device: HashMap::new(),
|
||||||
|
characteristic_to_service: HashMap::new(),
|
||||||
|
descriptor_to_characteristic: HashMap::new(),
|
||||||
|
cached_devices: HashMap::new(),
|
||||||
|
cached_services: HashMap::new(),
|
||||||
|
cached_characteristics: HashMap::new(),
|
||||||
|
cached_descriptors: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(&mut self) {
|
||||||
|
while let Ok(msg) = self.receiver.recv() {
|
||||||
|
match msg {
|
||||||
|
BluetoothMethodMsg::RequestDevice(options, sender) => {
|
||||||
|
self.request_device(options, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GATTServerConnect(device_id, sender) => {
|
||||||
|
self.gatt_server_connect(device_id, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GATTServerDisconnect(device_id, sender) => {
|
||||||
|
self.gatt_server_disconnect(device_id, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetPrimaryService(device_id, uuid, sender) => {
|
||||||
|
self.get_primary_service(device_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetPrimaryServices(device_id, uuid, sender) => {
|
||||||
|
self.get_primary_services(device_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetCharacteristic(service_id, uuid, sender) => {
|
||||||
|
self.get_characteristic(service_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetCharacteristics(service_id, uuid, sender) => {
|
||||||
|
self.get_characteristics(service_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetDescriptor(characteristic_id, uuid, sender) => {
|
||||||
|
self.get_descriptor(characteristic_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::GetDescriptors(characteristic_id, uuid, sender) => {
|
||||||
|
self.get_descriptors(characteristic_id, uuid, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::ReadValue(id, sender) => {
|
||||||
|
self.read_value(id, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::WriteValue(id, value, sender) => {
|
||||||
|
self.write_value(id, value, sender)
|
||||||
|
},
|
||||||
|
BluetoothMethodMsg::Exit => {
|
||||||
|
break
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adapter
|
||||||
|
|
||||||
|
fn get_or_create_adapter(&mut self) -> Option<BluetoothAdapter> {
|
||||||
|
let adapter_valid = self.adapter.as_ref().map_or(false, |a| a.get_address().is_ok());
|
||||||
|
if !adapter_valid {
|
||||||
|
self.adapter = BluetoothAdapter::init().ok();
|
||||||
|
}
|
||||||
|
self.adapter.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Device
|
||||||
|
|
||||||
|
fn get_and_cache_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec<BluetoothDevice> {
|
||||||
|
let devices = adapter.get_devices().unwrap_or(vec!());
|
||||||
|
for device in &devices {
|
||||||
|
if let Ok(address) = device.get_address() {
|
||||||
|
self.cached_devices.insert(address, device.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.cached_devices.iter().map(|(_, d)| d.clone()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_device(&mut self, adapter: &mut BluetoothAdapter, device_id: &str) -> Option<&BluetoothDevice> {
|
||||||
|
return_if_cached!(self.cached_devices, device_id);
|
||||||
|
self.get_and_cache_devices(adapter);
|
||||||
|
return_if_cached!(self.cached_devices, device_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service
|
||||||
|
|
||||||
|
fn get_and_cache_gatt_services(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
device_id: &str)
|
||||||
|
-> Vec<BluetoothGATTService> {
|
||||||
|
let services = match self.get_device(adapter, device_id) {
|
||||||
|
Some(d) => d.get_gatt_services().unwrap_or(vec!()),
|
||||||
|
None => vec!(),
|
||||||
|
};
|
||||||
|
for service in &services {
|
||||||
|
self.cached_services.insert(service.get_object_path(), service.clone());
|
||||||
|
self.service_to_device.insert(service.get_object_path(), device_id.to_owned());
|
||||||
|
}
|
||||||
|
services
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_service(&mut self, adapter: &mut BluetoothAdapter, service_id: &str) -> Option<&BluetoothGATTService> {
|
||||||
|
return_if_cached!(self.cached_services, service_id);
|
||||||
|
let device_id = match self.service_to_device.get(service_id) {
|
||||||
|
Some(d) => d.clone(),
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
self.get_and_cache_gatt_services(adapter, &device_id);
|
||||||
|
return_if_cached!(self.cached_services, service_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_services_by_uuid(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
device_id: &str,
|
||||||
|
service_uuid: &str)
|
||||||
|
-> Vec<BluetoothGATTService> {
|
||||||
|
let services = self.get_and_cache_gatt_services(adapter, device_id);
|
||||||
|
services.into_iter().filter(|s| s.get_uuid().ok() == Some(service_uuid.to_string())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Characteristic
|
||||||
|
|
||||||
|
fn get_and_cache_gatt_characteristics(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
service_id: &str)
|
||||||
|
-> Vec<BluetoothGATTCharacteristic> {
|
||||||
|
let characteristics = match self.get_gatt_service(adapter, service_id) {
|
||||||
|
Some(s) => s.get_gatt_characteristics().unwrap_or(vec!()),
|
||||||
|
None => vec!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for characteristic in &characteristics {
|
||||||
|
self.cached_characteristics.insert(characteristic.get_object_path(), characteristic.clone());
|
||||||
|
self.characteristic_to_service.insert(characteristic.get_object_path(), service_id.to_owned());
|
||||||
|
}
|
||||||
|
characteristics
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_characteristic(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
characteristic_id: &str)
|
||||||
|
-> Option<&BluetoothGATTCharacteristic> {
|
||||||
|
return_if_cached!(self.cached_characteristics, characteristic_id);
|
||||||
|
let service_id = match self.characteristic_to_service.get(characteristic_id) {
|
||||||
|
Some(s) => s.clone(),
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
self.get_and_cache_gatt_characteristics(adapter, &service_id);
|
||||||
|
return_if_cached!(self.cached_characteristics, characteristic_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_characteristics_by_uuid(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
service_id: &str,
|
||||||
|
characteristic_uuid: &str)
|
||||||
|
-> Vec<BluetoothGATTCharacteristic> {
|
||||||
|
let characteristics = self.get_and_cache_gatt_characteristics(adapter, service_id);
|
||||||
|
characteristics.into_iter()
|
||||||
|
.filter(|c| c.get_uuid().ok() == Some(characteristic_uuid.to_string()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> Flags {
|
||||||
|
let mut props: Flags = Flags::empty();
|
||||||
|
let flags = characteristic.get_flags().unwrap_or(vec!());
|
||||||
|
for flag in flags {
|
||||||
|
match flag.as_ref() {
|
||||||
|
"broadcast" => props.insert(BROADCAST),
|
||||||
|
"read" => props.insert(READ),
|
||||||
|
"write_without_response" => props.insert(WRITE_WITHOUT_RESPONSE),
|
||||||
|
"write" => props.insert(WRITE),
|
||||||
|
"notify" => props.insert(NOTIFY),
|
||||||
|
"indicate" => props.insert(INDICATE),
|
||||||
|
"authenticated_signed_writes" => props.insert(AUTHENTICATED_SIGNED_WRITES),
|
||||||
|
"reliable_write" => props.insert(RELIABLE_WRITE),
|
||||||
|
"writable_auxiliaries" => props.insert(WRITABLE_AUXILIARIES),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
props
|
||||||
|
}
|
||||||
|
|
||||||
|
// Descriptor
|
||||||
|
|
||||||
|
fn get_and_cache_gatt_descriptors(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
characteristic_id: &str)
|
||||||
|
-> Vec<BluetoothGATTDescriptor> {
|
||||||
|
let descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) {
|
||||||
|
Some(c) => c.get_gatt_descriptors().unwrap_or(vec!()),
|
||||||
|
None => vec!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for descriptor in &descriptors {
|
||||||
|
self.cached_descriptors.insert(descriptor.get_object_path(), descriptor.clone());
|
||||||
|
self.descriptor_to_characteristic.insert(descriptor.get_object_path(), characteristic_id.to_owned());
|
||||||
|
}
|
||||||
|
descriptors
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_descriptor(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
descriptor_id: &str)
|
||||||
|
-> Option<&BluetoothGATTDescriptor> {
|
||||||
|
return_if_cached!(self.cached_descriptors, descriptor_id);
|
||||||
|
let characteristic_id = match self.descriptor_to_characteristic.get(descriptor_id) {
|
||||||
|
Some(c) => c.clone(),
|
||||||
|
None => return None,
|
||||||
|
};
|
||||||
|
self.get_and_cache_gatt_descriptors(adapter, &characteristic_id);
|
||||||
|
return_if_cached!(self.cached_descriptors, descriptor_id);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_gatt_descriptors_by_uuid(&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
characteristic_id: &str,
|
||||||
|
descriptor_uuid: &str)
|
||||||
|
-> Vec<BluetoothGATTDescriptor> {
|
||||||
|
let descriptors = self.get_and_cache_gatt_descriptors(adapter, characteristic_id);
|
||||||
|
descriptors.into_iter()
|
||||||
|
.filter(|d| d.get_uuid().ok() == Some(descriptor_uuid.to_string()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Methods
|
||||||
|
|
||||||
|
fn request_device(&mut self,
|
||||||
|
options: RequestDeviceoptions,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothDeviceMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let devices = self.get_and_cache_devices(&mut adapter);
|
||||||
|
if devices.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(DEVICE_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
let matched_devices: Vec<BluetoothDevice> = devices.into_iter()
|
||||||
|
.filter(|d| matches_filters(d, options.get_filters()))
|
||||||
|
.collect();
|
||||||
|
for device in matched_devices {
|
||||||
|
if let Ok(address) = device.get_address() {
|
||||||
|
let message = Ok(BluetoothDeviceMsg {
|
||||||
|
id: address,
|
||||||
|
name: device.get_name().ok(),
|
||||||
|
device_class: device.get_class().ok(),
|
||||||
|
vendor_id_source: device.get_vendor_id_source().ok(),
|
||||||
|
vendor_id: device.get_vendor_id().ok(),
|
||||||
|
product_id: device.get_product_id().ok(),
|
||||||
|
product_version: device.get_device_id().ok(),
|
||||||
|
appearance: device.get_appearance().ok(),
|
||||||
|
tx_power: device.get_tx_power().ok().map(|p| p as i8),
|
||||||
|
rssi: device.get_rssi().ok().map(|p| p as i8),
|
||||||
|
});
|
||||||
|
return drop(sender.send(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drop(sender.send(Err(String::from(DEVICE_MATCH_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gatt_server_connect(&mut self, device_id: String, sender: IpcSender<BluetoothResult<bool>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let connected = match self.get_device(&mut adapter, &device_id) {
|
||||||
|
Some(d) => {
|
||||||
|
if d.is_connected().unwrap_or(false) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
d.connect().is_ok()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => return drop(sender.send(Err(String::from(DEVICE_ERROR)))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(connected));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gatt_server_disconnect(&mut self, device_id: String, sender: IpcSender<BluetoothResult<bool>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let connected = match self.get_device(&mut adapter, &device_id) {
|
||||||
|
Some(d) => {
|
||||||
|
if d.is_connected().unwrap_or(false) {
|
||||||
|
d.disconnect().is_ok()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => return drop(sender.send(Err(String::from(DEVICE_ERROR)))),
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(connected));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_primary_service(&mut self,
|
||||||
|
device_id: String,
|
||||||
|
uuid: String,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothServiceMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let services = self.get_gatt_services_by_uuid(&mut adapter, &device_id, &uuid);
|
||||||
|
if services.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR))));
|
||||||
|
}
|
||||||
|
for service in services {
|
||||||
|
if service.is_primary().unwrap_or(false) {
|
||||||
|
if let Ok(uuid) = service.get_uuid() {
|
||||||
|
return drop(sender.send(Ok(BluetoothServiceMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
is_primary: true,
|
||||||
|
instance_id: service.get_object_path(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_primary_services(&mut self,
|
||||||
|
device_id: String,
|
||||||
|
uuid: Option<String>,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothServicesMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let services = match uuid {
|
||||||
|
Some(id) => self.get_gatt_services_by_uuid(&mut adapter, &device_id, &id),
|
||||||
|
None => self.get_and_cache_gatt_services(&mut adapter, &device_id),
|
||||||
|
};
|
||||||
|
if services.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR))));
|
||||||
|
}
|
||||||
|
let mut services_vec = vec!();
|
||||||
|
for service in services {
|
||||||
|
if service.is_primary().unwrap_or(false) {
|
||||||
|
if let Ok(uuid) = service.get_uuid() {
|
||||||
|
services_vec.push(BluetoothServiceMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
is_primary: true,
|
||||||
|
instance_id: service.get_object_path(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if services_vec.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(PRIMARY_SERVICE_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(services_vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_characteristic(&mut self,
|
||||||
|
service_id: String,
|
||||||
|
uuid: String,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothCharacteristicMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let characteristics = self.get_gatt_characteristics_by_uuid(&mut adapter, &service_id, &uuid);
|
||||||
|
if characteristics.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR))));
|
||||||
|
}
|
||||||
|
for characteristic in characteristics {
|
||||||
|
if let Ok(uuid) = characteristic.get_uuid() {
|
||||||
|
let properties = self.get_characteristic_properties(&characteristic);
|
||||||
|
let message = Ok(BluetoothCharacteristicMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
instance_id: characteristic.get_object_path(),
|
||||||
|
broadcast: properties.contains(BROADCAST),
|
||||||
|
read: properties.contains(READ),
|
||||||
|
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
|
||||||
|
write: properties.contains(WRITE),
|
||||||
|
notify: properties.contains(NOTIFY),
|
||||||
|
indicate: properties.contains(INDICATE),
|
||||||
|
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
|
||||||
|
reliable_write: properties.contains(RELIABLE_WRITE),
|
||||||
|
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
|
||||||
|
});
|
||||||
|
return drop(sender.send(message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_characteristics(&mut self,
|
||||||
|
service_id: String,
|
||||||
|
uuid: Option<String>,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothCharacteristicsMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let characteristics = match uuid {
|
||||||
|
Some(id) => self.get_gatt_characteristics_by_uuid(&mut adapter, &service_id, &id),
|
||||||
|
None => self.get_and_cache_gatt_characteristics(&mut adapter, &service_id),
|
||||||
|
};
|
||||||
|
if characteristics.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR))));
|
||||||
|
}
|
||||||
|
let mut characteristics_vec = vec!();
|
||||||
|
for characteristic in characteristics {
|
||||||
|
if let Ok(uuid) = characteristic.get_uuid() {
|
||||||
|
let properties = self.get_characteristic_properties(&characteristic);
|
||||||
|
characteristics_vec.push(
|
||||||
|
BluetoothCharacteristicMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
instance_id: characteristic.get_object_path(),
|
||||||
|
broadcast: properties.contains(BROADCAST),
|
||||||
|
read: properties.contains(READ),
|
||||||
|
write_without_response: properties.contains(WRITE_WITHOUT_RESPONSE),
|
||||||
|
write: properties.contains(WRITE),
|
||||||
|
notify: properties.contains(NOTIFY),
|
||||||
|
indicate: properties.contains(INDICATE),
|
||||||
|
authenticated_signed_writes: properties.contains(AUTHENTICATED_SIGNED_WRITES),
|
||||||
|
reliable_write: properties.contains(RELIABLE_WRITE),
|
||||||
|
writable_auxiliaries: properties.contains(WRITABLE_AUXILIARIES),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if characteristics_vec.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(CHARACTERISTIC_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = sender.send(Ok(characteristics_vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_descriptor(&mut self,
|
||||||
|
characteristic_id: String,
|
||||||
|
uuid: String,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothDescriptorMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let descriptors = self.get_gatt_descriptors_by_uuid(&mut adapter, &characteristic_id, &uuid);
|
||||||
|
if descriptors.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR))));
|
||||||
|
}
|
||||||
|
for descriptor in descriptors {
|
||||||
|
if let Ok(uuid) = descriptor.get_uuid() {
|
||||||
|
return drop(sender.send(Ok(BluetoothDescriptorMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
instance_id: descriptor.get_object_path(),
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR))));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_descriptors(&mut self,
|
||||||
|
characteristic_id: String,
|
||||||
|
uuid: Option<String>,
|
||||||
|
sender: IpcSender<BluetoothResult<BluetoothDescriptorsMsg>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let descriptors = match uuid {
|
||||||
|
Some(id) => self.get_gatt_descriptors_by_uuid(&mut adapter, &characteristic_id, &id),
|
||||||
|
None => self.get_and_cache_gatt_descriptors(&mut adapter, &characteristic_id),
|
||||||
|
};
|
||||||
|
if descriptors.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR))));
|
||||||
|
}
|
||||||
|
let mut descriptors_vec = vec!();
|
||||||
|
for descriptor in descriptors {
|
||||||
|
if let Ok(uuid) = descriptor.get_uuid() {
|
||||||
|
descriptors_vec.push(BluetoothDescriptorMsg {
|
||||||
|
uuid: uuid,
|
||||||
|
instance_id: descriptor.get_object_path(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if descriptors_vec.is_empty() {
|
||||||
|
return drop(sender.send(Err(String::from(DESCRIPTOR_ERROR))));
|
||||||
|
}
|
||||||
|
let _ = sender.send(Ok(descriptors_vec));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_value(&mut self, id: String, sender: IpcSender<BluetoothResult<Vec<u8>>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let mut value = self.get_gatt_characteristic(&mut adapter, &id)
|
||||||
|
.map(|c| c.read_value().unwrap_or(vec![]));
|
||||||
|
if value.is_none() {
|
||||||
|
value = self.get_gatt_descriptor(&mut adapter, &id)
|
||||||
|
.map(|d| d.read_value().unwrap_or(vec![]));
|
||||||
|
}
|
||||||
|
let _ = sender.send(value.ok_or(String::from(VALUE_ERROR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn write_value(&mut self, id: String, value: Vec<u8>, sender: IpcSender<BluetoothResult<bool>>) {
|
||||||
|
let mut adapter = match self.get_or_create_adapter() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return drop(sender.send(Err(String::from(ADAPTER_ERROR)))),
|
||||||
|
};
|
||||||
|
let mut result = self.get_gatt_characteristic(&mut adapter, &id)
|
||||||
|
.map(|c| c.write_value(value.clone()));
|
||||||
|
if result.is_none() {
|
||||||
|
result = self.get_gatt_descriptor(&mut adapter, &id)
|
||||||
|
.map(|d| d.write_value(value.clone()));
|
||||||
|
}
|
||||||
|
let message = match result {
|
||||||
|
Some(v) => match v {
|
||||||
|
Ok(_) => Ok(true),
|
||||||
|
Err(e) => return drop(sender.send(Err(e.to_string()))),
|
||||||
|
},
|
||||||
|
None => return drop(sender.send(Err(String::from(VALUE_ERROR)))),
|
||||||
|
};
|
||||||
|
let _ = sender.send(message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,8 +11,11 @@
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate bitflags;
|
||||||
extern crate brotli;
|
extern crate brotli;
|
||||||
extern crate cookie as cookie_rs;
|
extern crate cookie as cookie_rs;
|
||||||
|
extern crate device;
|
||||||
extern crate devtools_traits;
|
extern crate devtools_traits;
|
||||||
extern crate flate2;
|
extern crate flate2;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
|
@ -39,6 +42,7 @@ extern crate webrender_traits;
|
||||||
extern crate websocket;
|
extern crate websocket;
|
||||||
|
|
||||||
pub mod about_loader;
|
pub mod about_loader;
|
||||||
|
pub mod bluetooth_thread;
|
||||||
pub mod chrome_loader;
|
pub mod chrome_loader;
|
||||||
pub mod cookie;
|
pub mod cookie;
|
||||||
pub mod cookie_storage;
|
pub mod cookie_storage;
|
||||||
|
|
93
components/net_traits/bluetooth_scanfilter.rs
Normal file
93
components/net_traits/bluetooth_scanfilter.rs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
/* 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::slice::Iter;
|
||||||
|
|
||||||
|
// A device name can never be longer than 29 bytes. An adv packet is at most
|
||||||
|
// 31 bytes long. The length and identifier of the length field take 2 bytes.
|
||||||
|
// That leaves 29 bytes for the name.
|
||||||
|
const MAX_NAME_LENGTH: usize = 29;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct ServiceUUIDSequence(Vec<String>);
|
||||||
|
|
||||||
|
impl ServiceUUIDSequence {
|
||||||
|
pub fn new(vec: Vec<String>) -> ServiceUUIDSequence {
|
||||||
|
ServiceUUIDSequence(vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothScanfilter {
|
||||||
|
name: String,
|
||||||
|
name_prefix: String,
|
||||||
|
services: ServiceUUIDSequence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BluetoothScanfilter {
|
||||||
|
pub fn new(name: String, name_prefix: String, services: Vec<String>) -> BluetoothScanfilter {
|
||||||
|
BluetoothScanfilter {
|
||||||
|
name: name,
|
||||||
|
name_prefix: name_prefix,
|
||||||
|
services: ServiceUUIDSequence::new(services),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name(&self) -> &str {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_name_prefix(&self) -> &str {
|
||||||
|
&self.name_prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_services(&self) -> &[String] {
|
||||||
|
&self.services.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty_or_invalid(&self) -> bool {
|
||||||
|
(self.name.is_empty() && self.name_prefix.is_empty() && self.get_services().is_empty()) ||
|
||||||
|
self.name.len() > MAX_NAME_LENGTH ||
|
||||||
|
self.name_prefix.len() > MAX_NAME_LENGTH
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothScanfilterSequence(Vec<BluetoothScanfilter>);
|
||||||
|
|
||||||
|
impl BluetoothScanfilterSequence {
|
||||||
|
pub fn new(vec: Vec<BluetoothScanfilter>) -> BluetoothScanfilterSequence {
|
||||||
|
BluetoothScanfilterSequence(vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_empty_or_invalid_filter(&self) -> bool {
|
||||||
|
self.0.is_empty() ||
|
||||||
|
self.0.iter().any(BluetoothScanfilter::is_empty_or_invalid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> Iter<BluetoothScanfilter> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct RequestDeviceoptions {
|
||||||
|
filters: BluetoothScanfilterSequence,
|
||||||
|
optional_services: ServiceUUIDSequence,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestDeviceoptions {
|
||||||
|
pub fn new(filters: BluetoothScanfilterSequence,
|
||||||
|
services: ServiceUUIDSequence)
|
||||||
|
-> RequestDeviceoptions {
|
||||||
|
RequestDeviceoptions {
|
||||||
|
filters: filters,
|
||||||
|
optional_services: services,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_filters(&self) -> &BluetoothScanfilterSequence {
|
||||||
|
&self.filters
|
||||||
|
}
|
||||||
|
}
|
75
components/net_traits/bluetooth_thread.rs
Normal file
75
components/net_traits/bluetooth_thread.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/* 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 bluetooth_scanfilter::RequestDeviceoptions;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothDeviceMsg {
|
||||||
|
// Bluetooth Device properties
|
||||||
|
pub id: String,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub device_class: Option<u32>,
|
||||||
|
pub vendor_id_source: Option<String>,
|
||||||
|
pub vendor_id: Option<u32>,
|
||||||
|
pub product_id: Option<u32>,
|
||||||
|
pub product_version: Option<u32>,
|
||||||
|
// Advertisiong Data properties
|
||||||
|
pub appearance: Option<u16>,
|
||||||
|
pub tx_power: Option<i8>,
|
||||||
|
pub rssi: Option<i8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothServiceMsg {
|
||||||
|
pub uuid: String,
|
||||||
|
pub is_primary: bool,
|
||||||
|
pub instance_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothCharacteristicMsg {
|
||||||
|
// Characteristic
|
||||||
|
pub uuid: String,
|
||||||
|
pub instance_id: String,
|
||||||
|
// Characteristic properties
|
||||||
|
pub broadcast: bool,
|
||||||
|
pub read: bool,
|
||||||
|
pub write_without_response: bool,
|
||||||
|
pub write: bool,
|
||||||
|
pub notify: bool,
|
||||||
|
pub indicate: bool,
|
||||||
|
pub authenticated_signed_writes: bool,
|
||||||
|
pub reliable_write: bool,
|
||||||
|
pub writable_auxiliaries: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub struct BluetoothDescriptorMsg {
|
||||||
|
pub uuid: String,
|
||||||
|
pub instance_id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type BluetoothServicesMsg = Vec<BluetoothServiceMsg>;
|
||||||
|
|
||||||
|
pub type BluetoothCharacteristicsMsg = Vec<BluetoothCharacteristicMsg>;
|
||||||
|
|
||||||
|
pub type BluetoothDescriptorsMsg = Vec<BluetoothDescriptorMsg>;
|
||||||
|
|
||||||
|
pub type BluetoothResult<T> = Result<T, String>;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum BluetoothMethodMsg {
|
||||||
|
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResult<BluetoothDeviceMsg>>),
|
||||||
|
GATTServerConnect(String, IpcSender<BluetoothResult<bool>>),
|
||||||
|
GATTServerDisconnect(String, IpcSender<BluetoothResult<bool>>),
|
||||||
|
GetPrimaryService(String, String, IpcSender<BluetoothResult<BluetoothServiceMsg>>),
|
||||||
|
GetPrimaryServices(String, Option<String>, IpcSender<BluetoothResult<BluetoothServicesMsg>>),
|
||||||
|
GetCharacteristic(String, String, IpcSender<BluetoothResult<BluetoothCharacteristicMsg>>),
|
||||||
|
GetCharacteristics(String, Option<String>, IpcSender<BluetoothResult<BluetoothCharacteristicsMsg>>),
|
||||||
|
GetDescriptor(String, String, IpcSender<BluetoothResult<BluetoothDescriptorMsg>>),
|
||||||
|
GetDescriptors(String, Option<String>, IpcSender<BluetoothResult<BluetoothDescriptorsMsg>>),
|
||||||
|
ReadValue(String, IpcSender<BluetoothResult<Vec<u8>>>),
|
||||||
|
WriteValue(String, Vec<u8>, IpcSender<BluetoothResult<bool>>),
|
||||||
|
Exit,
|
||||||
|
}
|
|
@ -40,6 +40,8 @@ use std::thread;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use websocket::header;
|
use websocket::header;
|
||||||
|
|
||||||
|
pub mod bluetooth_scanfilter;
|
||||||
|
pub mod bluetooth_thread;
|
||||||
pub mod hosts;
|
pub mod hosts;
|
||||||
pub mod image_cache_thread;
|
pub mod image_cache_thread;
|
||||||
pub mod net_error_list;
|
pub mod net_error_list;
|
||||||
|
|
|
@ -2,12 +2,38 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use core::clone::Clone;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothBinding;
|
use dom::bindings::codegen::Bindings::BluetoothBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothBinding::BluetoothMethods;
|
use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothScanFilter, BluetoothMethods};
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::VendorIDSource;
|
||||||
|
use dom::bindings::error::Error::Type;
|
||||||
|
use dom::bindings::error::Fallible;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::Root;
|
use dom::bindings::js::Root;
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
|
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
|
||||||
use dom::bluetoothdevice::BluetoothDevice;
|
use dom::bluetoothdevice::BluetoothDevice;
|
||||||
|
use dom::bluetoothuuid::BluetoothUUID;
|
||||||
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net_traits::bluetooth_scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence};
|
||||||
|
use net_traits::bluetooth_scanfilter::{RequestDeviceoptions, ServiceUUIDSequence};
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
|
use util::str::DOMString;
|
||||||
|
|
||||||
|
const FILTER_EMPTY_ERROR: &'static str = "'filters' member must be non - empty to find any devices.";
|
||||||
|
const FILTER_ERROR: &'static str = "A filter must restrict the devices in some way.";
|
||||||
|
const FILTER_NAME_TOO_LONG_ERROR: &'static str = "A 'name' or 'namePrefix' can't be longer then 29 bytes.";
|
||||||
|
// 248 is the maximum number of UTF-8 code units in a Bluetooth Device Name.
|
||||||
|
const MAX_DEVICE_NAME_LENGTH: usize = 248;
|
||||||
|
// A device name can never be longer than 29 bytes.
|
||||||
|
// An advertising packet is at most 31 bytes long.
|
||||||
|
// The length and identifier of the length field take 2 bytes.
|
||||||
|
// That leaves 29 bytes for the name.
|
||||||
|
const MAX_FILTER_NAME_LENGTH: usize = 29;
|
||||||
|
const NAME_PREFIX_ERROR: &'static str = "'namePrefix', if present, must be non - empty.";
|
||||||
|
const NAME_TOO_LONG_ERROR: &'static str = "A device name can't be longer than 248 bytes.";
|
||||||
|
const SERVICE_ERROR: &'static str = "'services', if present, must contain at least one service.";
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -27,13 +53,113 @@ impl Bluetooth {
|
||||||
global,
|
global,
|
||||||
BluetoothBinding::Wrap)
|
BluetoothBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let global_root = self.global();
|
||||||
|
let global_ref = global_root.r();
|
||||||
|
global_ref.as_window().bluetooth_thread()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn canonicalize_filter(filter: &BluetoothScanFilter, global: GlobalRef) -> Fallible<BluetoothScanfilter> {
|
||||||
|
if filter.services.is_none() && filter.name.is_none() && filter.namePrefix.is_none() {
|
||||||
|
return Err(Type(FILTER_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut services_vec = vec!();
|
||||||
|
if let Some(ref services) = filter.services {
|
||||||
|
if services.is_empty() {
|
||||||
|
return Err(Type(SERVICE_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
for service in services {
|
||||||
|
services_vec.push(try!(BluetoothUUID::GetService(global, service.clone())).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut name = String::new();
|
||||||
|
if let Some(ref filter_name) = filter.name {
|
||||||
|
//NOTE: DOMString::len() gives back the size in bytes
|
||||||
|
if filter_name.len() > MAX_DEVICE_NAME_LENGTH {
|
||||||
|
return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
if filter_name.len() > MAX_FILTER_NAME_LENGTH {
|
||||||
|
return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
name = filter_name.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut name_prefix = String::new();
|
||||||
|
if let Some(ref filter_name_prefix) = filter.namePrefix {
|
||||||
|
if filter_name_prefix.is_empty() {
|
||||||
|
return Err(Type(NAME_PREFIX_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
if filter_name_prefix.len() > MAX_DEVICE_NAME_LENGTH {
|
||||||
|
return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
if filter_name_prefix.len() > MAX_FILTER_NAME_LENGTH {
|
||||||
|
return Err(Type(FILTER_NAME_TOO_LONG_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
name_prefix = filter_name_prefix.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(BluetoothScanfilter::new(name, name_prefix, services_vec))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_request_device_options(options: &RequestDeviceOptions,
|
||||||
|
global: GlobalRef)
|
||||||
|
-> Fallible<RequestDeviceoptions> {
|
||||||
|
if options.filters.is_empty() {
|
||||||
|
return Err(Type(FILTER_EMPTY_ERROR.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut filters = vec!();
|
||||||
|
for filter in &options.filters {
|
||||||
|
filters.push(try!(canonicalize_filter(&filter, global)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut optional_services = vec!();
|
||||||
|
if let Some(ref opt_services) = options.optionalServices {
|
||||||
|
for opt_service in opt_services {
|
||||||
|
optional_services.push(try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(filters),
|
||||||
|
ServiceUUIDSequence::new(optional_services)))
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothMethods for Bluetooth {
|
impl BluetoothMethods for Bluetooth {
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
||||||
fn RequestDevice(&self) -> Option<Root<BluetoothDevice>> {
|
fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> {
|
||||||
//UNIMPLEMENTED
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
None
|
let option = try!(convert_request_device_options(option, self.global().r()));
|
||||||
|
self.get_bluetooth_thread().send(BluetoothMethodMsg::RequestDevice(option, sender)).unwrap();
|
||||||
|
let device = receiver.recv().unwrap();
|
||||||
|
match device {
|
||||||
|
Ok(device) => {
|
||||||
|
let ad_data = BluetoothAdvertisingData::new(self.global().r(),
|
||||||
|
device.appearance,
|
||||||
|
device.tx_power,
|
||||||
|
device.rssi);
|
||||||
|
let vendor_id_source = device.vendor_id_source.map(|vid| match vid.as_str() {
|
||||||
|
"bluetooth" => VendorIDSource::Bluetooth,
|
||||||
|
"usb" => VendorIDSource::Usb,
|
||||||
|
_ => VendorIDSource::Unknown,
|
||||||
|
});
|
||||||
|
Ok(BluetoothDevice::new(self.global().r(),
|
||||||
|
DOMString::from(device.id),
|
||||||
|
device.name.map(DOMString::from),
|
||||||
|
&ad_data,
|
||||||
|
device.device_class,
|
||||||
|
vendor_id_source,
|
||||||
|
device.vendor_id,
|
||||||
|
device.product_id,
|
||||||
|
device.product_version))
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,13 +12,16 @@ use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct BluetoothAdvertisingData {
|
pub struct BluetoothAdvertisingData {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
appearance: u16,
|
appearance: Option<u16>,
|
||||||
txPower: i8,
|
txPower: Option<i8>,
|
||||||
rssi: i8,
|
rssi: Option<i8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothAdvertisingData {
|
impl BluetoothAdvertisingData {
|
||||||
pub fn new_inherited(appearance: u16, txPower: i8, rssi: i8) -> BluetoothAdvertisingData {
|
pub fn new_inherited(appearance: Option<u16>,
|
||||||
|
txPower: Option<i8>,
|
||||||
|
rssi: Option<i8>)
|
||||||
|
-> BluetoothAdvertisingData {
|
||||||
BluetoothAdvertisingData {
|
BluetoothAdvertisingData {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
appearance: appearance,
|
appearance: appearance,
|
||||||
|
@ -27,7 +30,11 @@ impl BluetoothAdvertisingData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef, appearance: u16, txPower: i8, rssi: i8) -> Root<BluetoothAdvertisingData> {
|
pub fn new(global: GlobalRef,
|
||||||
|
appearance: Option<u16>,
|
||||||
|
txPower: Option<i8>,
|
||||||
|
rssi: Option<i8>)
|
||||||
|
-> Root<BluetoothAdvertisingData> {
|
||||||
reflect_dom_object(box BluetoothAdvertisingData::new_inherited(appearance,
|
reflect_dom_object(box BluetoothAdvertisingData::new_inherited(appearance,
|
||||||
txPower,
|
txPower,
|
||||||
rssi),
|
rssi),
|
||||||
|
@ -39,16 +46,16 @@ impl BluetoothAdvertisingData {
|
||||||
impl BluetoothAdvertisingDataMethods for BluetoothAdvertisingData {
|
impl BluetoothAdvertisingDataMethods for BluetoothAdvertisingData {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-appearance
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-appearance
|
||||||
fn GetAppearance(&self) -> Option<u16> {
|
fn GetAppearance(&self) -> Option<u16> {
|
||||||
Some(self.appearance)
|
self.appearance
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-txpower
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-txpower
|
||||||
fn GetTxPower(&self) -> Option<i8> {
|
fn GetTxPower(&self) -> Option<i8> {
|
||||||
Some(self.txPower)
|
self.txPower
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-rssi
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-rssi
|
||||||
fn GetRssi(&self) -> Option<i8> {
|
fn GetRssi(&self) -> Option<i8> {
|
||||||
Some(self.rssi)
|
self.rssi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding;
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::{BluetoothDeviceMethods, VendorIDSource};
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::{BluetoothDeviceMethods, VendorIDSource};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, Root, MutHeap};
|
use dom::bindings::js::{JS, Root, MutHeap, MutNullableHeap};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
|
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
|
||||||
use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer;
|
use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
@ -16,26 +16,25 @@ use util::str::DOMString;
|
||||||
pub struct BluetoothDevice {
|
pub struct BluetoothDevice {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
id: DOMString,
|
id: DOMString,
|
||||||
name: DOMString,
|
name: Option<DOMString>,
|
||||||
adData: MutHeap<JS<BluetoothAdvertisingData>>,
|
adData: MutHeap<JS<BluetoothAdvertisingData>>,
|
||||||
deviceClass: u32,
|
deviceClass: Option<u32>,
|
||||||
vendorIDSource: VendorIDSource,
|
vendorIDSource: Option<VendorIDSource>,
|
||||||
vendorID: u32,
|
vendorID: Option<u32>,
|
||||||
productID: u32,
|
productID: Option<u32>,
|
||||||
productVersion: u32,
|
productVersion: Option<u32>,
|
||||||
gatt: MutHeap<JS<BluetoothRemoteGATTServer>>,
|
gatt: MutNullableHeap<JS<BluetoothRemoteGATTServer>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothDevice {
|
impl BluetoothDevice {
|
||||||
pub fn new_inherited(id: DOMString,
|
pub fn new_inherited(id: DOMString,
|
||||||
name: DOMString,
|
name: Option<DOMString>,
|
||||||
adData: &BluetoothAdvertisingData,
|
adData: &BluetoothAdvertisingData,
|
||||||
deviceClass: u32,
|
deviceClass: Option<u32>,
|
||||||
vendorIDSource: VendorIDSource,
|
vendorIDSource: Option<VendorIDSource>,
|
||||||
vendorID: u32,
|
vendorID: Option<u32>,
|
||||||
productID: u32,
|
productID: Option<u32>,
|
||||||
productVersion: u32,
|
productVersion: Option<u32>)
|
||||||
gatt: &BluetoothRemoteGATTServer)
|
|
||||||
-> BluetoothDevice {
|
-> BluetoothDevice {
|
||||||
BluetoothDevice {
|
BluetoothDevice {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
|
@ -47,20 +46,19 @@ impl BluetoothDevice {
|
||||||
vendorID: vendorID,
|
vendorID: vendorID,
|
||||||
productID: productID,
|
productID: productID,
|
||||||
productVersion: productVersion,
|
productVersion: productVersion,
|
||||||
gatt: MutHeap::new(gatt),
|
gatt: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef,
|
pub fn new(global: GlobalRef,
|
||||||
id: DOMString,
|
id: DOMString,
|
||||||
name: DOMString,
|
name: Option<DOMString>,
|
||||||
adData: &BluetoothAdvertisingData,
|
adData: &BluetoothAdvertisingData,
|
||||||
deviceClass: u32,
|
deviceClass: Option<u32>,
|
||||||
vendorIDSource: VendorIDSource,
|
vendorIDSource: Option<VendorIDSource>,
|
||||||
vendorID: u32,
|
vendorID: Option<u32>,
|
||||||
productID: u32,
|
productID: Option<u32>,
|
||||||
productVersion: u32,
|
productVersion: Option<u32>)
|
||||||
gatt: &BluetoothRemoteGATTServer)
|
|
||||||
-> Root<BluetoothDevice> {
|
-> Root<BluetoothDevice> {
|
||||||
reflect_dom_object(box BluetoothDevice::new_inherited(id,
|
reflect_dom_object(box BluetoothDevice::new_inherited(id,
|
||||||
name,
|
name,
|
||||||
|
@ -69,8 +67,7 @@ impl BluetoothDevice {
|
||||||
vendorIDSource,
|
vendorIDSource,
|
||||||
vendorID,
|
vendorID,
|
||||||
productID,
|
productID,
|
||||||
productVersion,
|
productVersion),
|
||||||
gatt),
|
|
||||||
global,
|
global,
|
||||||
BluetoothDeviceBinding::Wrap)
|
BluetoothDeviceBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
@ -85,7 +82,7 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-name
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-name
|
||||||
fn GetName(&self) -> Option<DOMString> {
|
fn GetName(&self) -> Option<DOMString> {
|
||||||
Some(self.name.clone())
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-addata
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-addata
|
||||||
|
@ -95,31 +92,31 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-deviceclass
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-deviceclass
|
||||||
fn GetDeviceClass(&self) -> Option<u32> {
|
fn GetDeviceClass(&self) -> Option<u32> {
|
||||||
Some(self.deviceClass)
|
self.deviceClass
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendoridsource
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendoridsource
|
||||||
fn GetVendorIDSource(&self) -> Option<VendorIDSource> {
|
fn GetVendorIDSource(&self) -> Option<VendorIDSource> {
|
||||||
Some(self.vendorIDSource)
|
self.vendorIDSource
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendorid
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendorid
|
||||||
fn GetVendorID(&self) -> Option<u32> {
|
fn GetVendorID(&self) -> Option<u32> {
|
||||||
Some(self.vendorID)
|
self.vendorID
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productid
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productid
|
||||||
fn GetProductID(&self) -> Option<u32> {
|
fn GetProductID(&self) -> Option<u32> {
|
||||||
Some(self.productID)
|
self.productID
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productversion
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productversion
|
||||||
fn GetProductVersion(&self) -> Option<u32> {
|
fn GetProductVersion(&self) -> Option<u32> {
|
||||||
Some(self.productVersion)
|
self.productVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
||||||
fn Gatt(&self) -> Root<BluetoothRemoteGATTServer> {
|
fn Gatt(&self) -> Root<BluetoothRemoteGATTServer> {
|
||||||
self.gatt.get()
|
self.gatt.or_init(|| BluetoothRemoteGATTServer::new(self.global().r(), self))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,25 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::cell::DOMRefCell;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
||||||
BluetoothRemoteGATTCharacteristicMethods;
|
BluetoothRemoteGATTCharacteristicMethods;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
||||||
|
use dom::bindings::error::Error::{Network, Type};
|
||||||
|
use dom::bindings::error::{Fallible, ErrorResult};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, MutHeap, Root};
|
use dom::bindings::js::{JS, MutHeap, Root};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::ByteString;
|
use dom::bindings::str::ByteString;
|
||||||
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
|
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
|
||||||
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
|
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
|
||||||
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
|
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
|
||||||
|
use dom::bluetoothuuid::{BluetoothDescriptorUUID, BluetoothUUID};
|
||||||
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
|
||||||
|
@ -21,34 +30,49 @@ pub struct BluetoothRemoteGATTCharacteristic {
|
||||||
service: MutHeap<JS<BluetoothRemoteGATTService>>,
|
service: MutHeap<JS<BluetoothRemoteGATTService>>,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
properties: MutHeap<JS<BluetoothCharacteristicProperties>>,
|
properties: MutHeap<JS<BluetoothCharacteristicProperties>>,
|
||||||
value: Option<ByteString>,
|
value: DOMRefCell<Option<ByteString>>,
|
||||||
|
instanceID: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTCharacteristic {
|
impl BluetoothRemoteGATTCharacteristic {
|
||||||
pub fn new_inherited(service: &BluetoothRemoteGATTService,
|
pub fn new_inherited(service: &BluetoothRemoteGATTService,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
properties: &BluetoothCharacteristicProperties)
|
properties: &BluetoothCharacteristicProperties,
|
||||||
|
instanceID: String)
|
||||||
-> BluetoothRemoteGATTCharacteristic {
|
-> BluetoothRemoteGATTCharacteristic {
|
||||||
BluetoothRemoteGATTCharacteristic {
|
BluetoothRemoteGATTCharacteristic {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
service: MutHeap::new(service),
|
service: MutHeap::new(service),
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
properties: MutHeap::new(properties),
|
properties: MutHeap::new(properties),
|
||||||
value: None,
|
value: DOMRefCell::new(None),
|
||||||
|
instanceID: instanceID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef,
|
pub fn new(global: GlobalRef,
|
||||||
service: &BluetoothRemoteGATTService,
|
service: &BluetoothRemoteGATTService,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
properties: &BluetoothCharacteristicProperties)
|
properties: &BluetoothCharacteristicProperties,
|
||||||
|
instanceID: String)
|
||||||
-> Root<BluetoothRemoteGATTCharacteristic> {
|
-> Root<BluetoothRemoteGATTCharacteristic> {
|
||||||
reflect_dom_object(box BluetoothRemoteGATTCharacteristic::new_inherited(service,
|
reflect_dom_object(box BluetoothRemoteGATTCharacteristic::new_inherited(service,
|
||||||
uuid,
|
uuid,
|
||||||
properties),
|
properties,
|
||||||
|
instanceID),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTCharacteristicBinding::Wrap)
|
BluetoothRemoteGATTCharacteristicBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let global_root = self.global();
|
||||||
|
let global_ref = global_root.r();
|
||||||
|
global_ref.as_window().bluetooth_thread()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance_id(&self) -> String {
|
||||||
|
self.instanceID.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic {
|
impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteristic {
|
||||||
|
@ -69,19 +93,89 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
||||||
fn GetDescriptor(&self) -> Option<Root<BluetoothRemoteGATTDescriptor>> {
|
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> {
|
||||||
//UNIMPLEMENTED
|
let uuid = try!(BluetoothUUID::GetDescriptor(self.global().r(), descriptor)).to_string();
|
||||||
None
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetDescriptor(self.get_instance_id(), uuid, sender)).unwrap();
|
||||||
|
let descriptor = receiver.recv().unwrap();
|
||||||
|
match descriptor {
|
||||||
|
Ok(descriptor) => {
|
||||||
|
Ok(BluetoothRemoteGATTDescriptor::new(self.global().r(),
|
||||||
|
self,
|
||||||
|
DOMString::from(descriptor.uuid),
|
||||||
|
descriptor.instance_id))
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
|
||||||
|
fn GetDescriptors(&self,
|
||||||
|
descriptor: Option<BluetoothDescriptorUUID>)
|
||||||
|
-> Fallible<Vec<Root<BluetoothRemoteGATTDescriptor>>> {
|
||||||
|
let mut uuid: Option<String> = None;
|
||||||
|
if let Some(d) = descriptor {
|
||||||
|
uuid = Some(try!(BluetoothUUID::GetDescriptor(self.global().r(), d)).to_string())
|
||||||
|
};
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetDescriptors(self.get_instance_id(), uuid, sender)).unwrap();
|
||||||
|
let descriptors_vec = receiver.recv().unwrap();
|
||||||
|
match descriptors_vec {
|
||||||
|
Ok(descriptor_vec) => {
|
||||||
|
Ok(descriptor_vec.into_iter()
|
||||||
|
.map(|desc| BluetoothRemoteGATTDescriptor::new(self.global().r(),
|
||||||
|
self,
|
||||||
|
DOMString::from(desc.uuid),
|
||||||
|
desc.instance_id))
|
||||||
|
.collect())
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
|
||||||
fn GetValue(&self) -> Option<ByteString> {
|
fn GetValue(&self) -> Option<ByteString> {
|
||||||
self.value.clone()
|
self.value.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
|
||||||
fn ReadValue(&self) -> ByteString {
|
fn ReadValue(&self) -> Fallible<ByteString> {
|
||||||
//UNIMPLEMENTED
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
ByteString::new(vec!())
|
if !self.Service().Device().Gatt().Connected() {
|
||||||
|
return Err(Network)
|
||||||
|
}
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
|
||||||
|
let result = receiver.recv().unwrap();
|
||||||
|
let value = match result {
|
||||||
|
Ok(val) => {
|
||||||
|
ByteString::new(val)
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
return Err(Type(error))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
*self.value.borrow_mut() = Some(value.clone());
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
|
||||||
|
fn WriteValue(&self, value: Vec<u8>) -> ErrorResult {
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap();
|
||||||
|
let result = receiver.recv().unwrap();
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,23 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::cell::DOMRefCell;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
|
||||||
|
BluetoothRemoteGATTCharacteristicMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
||||||
|
use dom::bindings::error::Error::{Type, Network};
|
||||||
|
use dom::bindings::error::{Fallible, ErrorResult};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, MutHeap, Root};
|
use dom::bindings::js::{JS, MutHeap, Root};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bindings::str::ByteString;
|
use dom::bindings::str::ByteString;
|
||||||
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
||||||
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
// http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor
|
// http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor
|
||||||
|
@ -17,30 +27,45 @@ pub struct BluetoothRemoteGATTDescriptor {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
characteristic: MutHeap<JS<BluetoothRemoteGATTCharacteristic>>,
|
characteristic: MutHeap<JS<BluetoothRemoteGATTCharacteristic>>,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
value: Option<ByteString>,
|
value: DOMRefCell<Option<ByteString>>,
|
||||||
|
instanceID: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTDescriptor {
|
impl BluetoothRemoteGATTDescriptor {
|
||||||
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic,
|
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||||
uuid: DOMString)
|
uuid: DOMString,
|
||||||
|
instanceID: String)
|
||||||
-> BluetoothRemoteGATTDescriptor {
|
-> BluetoothRemoteGATTDescriptor {
|
||||||
BluetoothRemoteGATTDescriptor {
|
BluetoothRemoteGATTDescriptor {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
characteristic: MutHeap::new(characteristic),
|
characteristic: MutHeap::new(characteristic),
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
value: None,
|
value: DOMRefCell::new(None),
|
||||||
|
instanceID: instanceID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef,
|
pub fn new(global: GlobalRef,
|
||||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||||
uuid: DOMString)
|
uuid: DOMString,
|
||||||
|
instanceID: String)
|
||||||
-> Root<BluetoothRemoteGATTDescriptor>{
|
-> Root<BluetoothRemoteGATTDescriptor>{
|
||||||
reflect_dom_object(box BluetoothRemoteGATTDescriptor::new_inherited(characteristic,
|
reflect_dom_object(box BluetoothRemoteGATTDescriptor::new_inherited(characteristic,
|
||||||
uuid),
|
uuid,
|
||||||
|
instanceID),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTDescriptorBinding::Wrap)
|
BluetoothRemoteGATTDescriptorBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let global_root = self.global();
|
||||||
|
let global_ref = global_root.r();
|
||||||
|
global_ref.as_window().bluetooth_thread()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance_id(&self) -> String {
|
||||||
|
self.instanceID.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
|
@ -57,12 +82,41 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value
|
||||||
fn GetValue(&self) -> Option<ByteString> {
|
fn GetValue(&self) -> Option<ByteString> {
|
||||||
self.value.clone()
|
self.value.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
|
||||||
fn ReadValue(&self) -> ByteString {
|
fn ReadValue(&self) -> Fallible<ByteString> {
|
||||||
//UNIMPLEMENTED
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
ByteString::new(vec!())
|
if !self.Characteristic().Service().Device().Gatt().Connected() {
|
||||||
|
return Err(Network)
|
||||||
|
}
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
|
||||||
|
let result = receiver.recv().unwrap();
|
||||||
|
let value = match result {
|
||||||
|
Ok(val) => {
|
||||||
|
ByteString::new(val)
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
return Err(Type(error))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
*self.value.borrow_mut() = Some(value.clone());
|
||||||
|
Ok(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
|
||||||
|
fn WriteValue(&self, value: Vec<u8>) -> ErrorResult {
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap();
|
||||||
|
let result = receiver.recv().unwrap();
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,21 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
|
||||||
|
use dom::bindings::error::Error::Type;
|
||||||
|
use dom::bindings::error::{Fallible, ErrorResult};
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, MutHeap, Root};
|
use dom::bindings::js::{JS, MutHeap, Root};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
use dom::bluetoothdevice::BluetoothDevice;
|
use dom::bluetoothdevice::BluetoothDevice;
|
||||||
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
|
use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
|
||||||
|
use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
|
||||||
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use util::str::DOMString;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -20,21 +27,25 @@ pub struct BluetoothRemoteGATTServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTServer {
|
impl BluetoothRemoteGATTServer {
|
||||||
pub fn new_inherited(device: &BluetoothDevice, is_connected: bool) -> BluetoothRemoteGATTServer {
|
pub fn new_inherited(device: &BluetoothDevice) -> BluetoothRemoteGATTServer {
|
||||||
BluetoothRemoteGATTServer {
|
BluetoothRemoteGATTServer {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
device: MutHeap::new(device),
|
device: MutHeap::new(device),
|
||||||
connected: Cell::new(is_connected),
|
connected: Cell::new(false),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef, device: &BluetoothDevice, connected: bool) -> Root<BluetoothRemoteGATTServer> {
|
pub fn new(global: GlobalRef, device: &BluetoothDevice) -> Root<BluetoothRemoteGATTServer> {
|
||||||
reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited(
|
reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited(device),
|
||||||
device,
|
|
||||||
connected),
|
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTServerBinding::Wrap)
|
BluetoothRemoteGATTServerBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let global_root = self.global();
|
||||||
|
let global_ref = global_root.r();
|
||||||
|
global_ref.as_window().bluetooth_thread()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
||||||
|
@ -50,21 +61,85 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
|
||||||
fn Connect(&self) -> Root<BluetoothRemoteGATTServer> {
|
fn Connect(&self) -> Fallible<Root<BluetoothRemoteGATTServer>> {
|
||||||
if !self.connected.get() {
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
self.connected.set(true);
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GATTServerConnect(String::from(self.Device().Id()), sender)).unwrap();
|
||||||
|
let server = receiver.recv().unwrap();
|
||||||
|
match server {
|
||||||
|
Ok(connected) => {
|
||||||
|
self.connected.set(connected);
|
||||||
|
Ok(Root::from_ref(self))
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Root::from_ref(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
|
||||||
fn Disconnect(&self) {
|
fn Disconnect(&self) -> ErrorResult {
|
||||||
self.connected.set(false);
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap();
|
||||||
|
let server = receiver.recv().unwrap();
|
||||||
|
match server {
|
||||||
|
Ok(connected) => {
|
||||||
|
self.connected.set(connected);
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
|
||||||
fn GetPrimaryService(&self) -> Option<Root<BluetoothRemoteGATTService>> {
|
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> {
|
||||||
//UNIMPLEMENTED
|
let uuid = try!(BluetoothUUID::GetService(self.global().r(), service)).to_string();
|
||||||
None
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetPrimaryService(String::from(self.Device().Id()), uuid, sender)).unwrap();
|
||||||
|
let service = receiver.recv().unwrap();
|
||||||
|
match service {
|
||||||
|
Ok(service) => {
|
||||||
|
Ok(BluetoothRemoteGATTService::new(self.global().r(),
|
||||||
|
&self.device.get(),
|
||||||
|
DOMString::from(service.uuid),
|
||||||
|
service.is_primary,
|
||||||
|
service.instance_id))
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
|
||||||
|
fn GetPrimaryServices(&self,
|
||||||
|
service: Option<BluetoothServiceUUID>)
|
||||||
|
-> Fallible<Vec<Root<BluetoothRemoteGATTService>>> {
|
||||||
|
let mut uuid: Option<String> = None;
|
||||||
|
if let Some(s) = service {
|
||||||
|
uuid = Some(try!(BluetoothUUID::GetService(self.global().r(), s)).to_string())
|
||||||
|
};
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetPrimaryServices(String::from(self.Device().Id()), uuid, sender)).unwrap();
|
||||||
|
let services_vec = receiver.recv().unwrap();
|
||||||
|
match services_vec {
|
||||||
|
Ok(service_vec) => {
|
||||||
|
Ok(service_vec.into_iter()
|
||||||
|
.map(|service| BluetoothRemoteGATTService::new(self.global().r(),
|
||||||
|
&self.device.get(),
|
||||||
|
DOMString::from(service.uuid),
|
||||||
|
service.is_primary,
|
||||||
|
service.instance_id))
|
||||||
|
.collect())
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,17 @@
|
||||||
|
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding;
|
||||||
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
|
||||||
|
use dom::bindings::error::Error::Type;
|
||||||
|
use dom::bindings::error::Fallible;
|
||||||
use dom::bindings::global::GlobalRef;
|
use dom::bindings::global::GlobalRef;
|
||||||
use dom::bindings::js::{JS, MutHeap, Root};
|
use dom::bindings::js::{JS, MutHeap, Root};
|
||||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||||
|
use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
|
||||||
use dom::bluetoothdevice::BluetoothDevice;
|
use dom::bluetoothdevice::BluetoothDevice;
|
||||||
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
||||||
|
use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothUUID};
|
||||||
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
|
||||||
|
@ -18,32 +24,47 @@ pub struct BluetoothRemoteGATTService {
|
||||||
device: MutHeap<JS<BluetoothDevice>>,
|
device: MutHeap<JS<BluetoothDevice>>,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
isPrimary: bool,
|
isPrimary: bool,
|
||||||
|
instanceID: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTService {
|
impl BluetoothRemoteGATTService {
|
||||||
pub fn new_inherited(device: &BluetoothDevice,
|
pub fn new_inherited(device: &BluetoothDevice,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
isPrimary: bool)
|
isPrimary: bool,
|
||||||
|
instanceID: String)
|
||||||
-> BluetoothRemoteGATTService {
|
-> BluetoothRemoteGATTService {
|
||||||
BluetoothRemoteGATTService {
|
BluetoothRemoteGATTService {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
device: MutHeap::new(device),
|
device: MutHeap::new(device),
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
isPrimary: isPrimary,
|
isPrimary: isPrimary,
|
||||||
|
instanceID: instanceID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: GlobalRef,
|
pub fn new(global: GlobalRef,
|
||||||
device: &BluetoothDevice,
|
device: &BluetoothDevice,
|
||||||
uuid: DOMString,
|
uuid: DOMString,
|
||||||
isPrimary: bool)
|
isPrimary: bool,
|
||||||
|
instanceID: String)
|
||||||
-> Root<BluetoothRemoteGATTService> {
|
-> Root<BluetoothRemoteGATTService> {
|
||||||
reflect_dom_object(box BluetoothRemoteGATTService::new_inherited(device,
|
reflect_dom_object(box BluetoothRemoteGATTService::new_inherited(device,
|
||||||
uuid,
|
uuid,
|
||||||
isPrimary),
|
isPrimary,
|
||||||
|
instanceID),
|
||||||
global,
|
global,
|
||||||
BluetoothRemoteGATTServiceBinding::Wrap)
|
BluetoothRemoteGATTServiceBinding::Wrap)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
let global_root = self.global();
|
||||||
|
let global_ref = global_root.r();
|
||||||
|
global_ref.as_window().bluetooth_thread()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_instance_id(&self) -> String {
|
||||||
|
self.instanceID.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
||||||
|
@ -63,8 +84,75 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
||||||
fn GetCharacteristic(&self) -> Option<Root<BluetoothRemoteGATTCharacteristic>> {
|
fn GetCharacteristic(&self,
|
||||||
// UNIMPLEMENTED
|
characteristic: BluetoothCharacteristicUUID)
|
||||||
None
|
-> Fallible<Root<BluetoothRemoteGATTCharacteristic>> {
|
||||||
|
let uuid = try!(BluetoothUUID::GetCharacteristic(self.global().r(), characteristic)).to_string();
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetCharacteristic(self.get_instance_id(), uuid, sender)).unwrap();
|
||||||
|
let characteristic = receiver.recv().unwrap();
|
||||||
|
match characteristic {
|
||||||
|
Ok(characteristic) => {
|
||||||
|
let properties = BluetoothCharacteristicProperties::new(self.global().r(),
|
||||||
|
characteristic.broadcast,
|
||||||
|
characteristic.read,
|
||||||
|
characteristic.write_without_response,
|
||||||
|
characteristic.write,
|
||||||
|
characteristic.notify,
|
||||||
|
characteristic.indicate,
|
||||||
|
characteristic.authenticated_signed_writes,
|
||||||
|
characteristic.reliable_write,
|
||||||
|
characteristic.writable_auxiliaries);
|
||||||
|
Ok(BluetoothRemoteGATTCharacteristic::new(self.global().r(),
|
||||||
|
self,
|
||||||
|
DOMString::from(characteristic.uuid),
|
||||||
|
&properties,
|
||||||
|
characteristic.instance_id))
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
|
||||||
|
fn GetCharacteristics(&self,
|
||||||
|
characteristic: Option<BluetoothCharacteristicUUID>)
|
||||||
|
-> Fallible<Vec<Root<BluetoothRemoteGATTCharacteristic>>> {
|
||||||
|
let mut uuid: Option<String> = None;
|
||||||
|
if let Some(c) = characteristic {
|
||||||
|
uuid = Some(try!(BluetoothUUID::GetCharacteristic(self.global().r(), c)).to_string())
|
||||||
|
};
|
||||||
|
let mut characteristics = vec!();
|
||||||
|
let (sender, receiver) = ipc::channel().unwrap();
|
||||||
|
self.get_bluetooth_thread().send(
|
||||||
|
BluetoothMethodMsg::GetCharacteristics(self.get_instance_id(), uuid, sender)).unwrap();
|
||||||
|
let characteristics_vec = receiver.recv().unwrap();
|
||||||
|
match characteristics_vec {
|
||||||
|
Ok(characteristic_vec) => {
|
||||||
|
for characteristic in characteristic_vec {
|
||||||
|
let properties = BluetoothCharacteristicProperties::new(self.global().r(),
|
||||||
|
characteristic.broadcast,
|
||||||
|
characteristic.read,
|
||||||
|
characteristic.write_without_response,
|
||||||
|
characteristic.write,
|
||||||
|
characteristic.notify,
|
||||||
|
characteristic.indicate,
|
||||||
|
characteristic.authenticated_signed_writes,
|
||||||
|
characteristic.reliable_write,
|
||||||
|
characteristic.writable_auxiliaries);
|
||||||
|
characteristics.push(BluetoothRemoteGATTCharacteristic::new(self.global().r(),
|
||||||
|
self,
|
||||||
|
DOMString::from(characteristic.uuid),
|
||||||
|
&properties,
|
||||||
|
characteristic.instance_id));
|
||||||
|
}
|
||||||
|
Ok(characteristics)
|
||||||
|
},
|
||||||
|
Err(error) => {
|
||||||
|
Err(Type(error))
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ use regex::Regex;
|
||||||
use util::str::DOMString;
|
use util::str::DOMString;
|
||||||
|
|
||||||
pub type UUID = DOMString;
|
pub type UUID = DOMString;
|
||||||
|
pub type BluetoothServiceUUID = StringOrUnsignedLong;
|
||||||
|
pub type BluetoothCharacteristicUUID = StringOrUnsignedLong;
|
||||||
|
pub type BluetoothDescriptorUUID = StringOrUnsignedLong;
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -18,27 +21,246 @@ pub struct BluetoothUUID {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
}
|
}
|
||||||
|
|
||||||
const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
|
||||||
//TODO(zakorgy) create all the services
|
|
||||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||||
|
const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.service.alert_notification", 0x1811_u32),
|
("org.bluetooth.service.alert_notification", 0x1811_u32),
|
||||||
("org.bluetooth.service.automation_io", 0x1815_u32),
|
("org.bluetooth.service.automation_io", 0x1815_u32),
|
||||||
("org.bluetooth.service.battery_service", 0x180f_u32)
|
("org.bluetooth.service.battery_service", 0x180f_u32),
|
||||||
|
("org.bluetooth.service.blood_pressure", 0x1810_u32),
|
||||||
|
("org.bluetooth.service.body_composition", 0x181b_u32),
|
||||||
|
("org.bluetooth.service.bond_management", 0x181e_u32),
|
||||||
|
("org.bluetooth.service.continuous_glucose_monitoring", 0x181f_u32),
|
||||||
|
("org.bluetooth.service.current_time", 0x1805_u32),
|
||||||
|
("org.bluetooth.service.cycling_power", 0x1818_u32),
|
||||||
|
("org.bluetooth.service.cycling_speed_and_cadence", 0x1816_u32),
|
||||||
|
("org.bluetooth.service.device_information", 0x180a_u32),
|
||||||
|
("org.bluetooth.service.environmental_sensing", 0x181a_u32),
|
||||||
|
("org.bluetooth.service.generic_access", 0x1800_u32),
|
||||||
|
("org.bluetooth.service.generic_attribute", 0x1801_u32),
|
||||||
|
("org.bluetooth.service.glucose", 0x1808_u32),
|
||||||
|
("org.bluetooth.service.health_thermometer", 0x1809_u32),
|
||||||
|
("org.bluetooth.service.heart_rate", 0x180d_u32),
|
||||||
|
("org.bluetooth.service.http_proxy", 0x1823_u32),
|
||||||
|
("org.bluetooth.service.human_interface_device", 0x1812_u32),
|
||||||
|
("org.bluetooth.service.immediate_alert", 0x1802_u32),
|
||||||
|
("org.bluetooth.service.indoor_positioning", 0x1821_u32),
|
||||||
|
("org.bluetooth.service.internet_protocol_support", 0x1820_u32),
|
||||||
|
("org.bluetooth.service.link_loss", 0x1803_u32),
|
||||||
|
("org.bluetooth.service.location_and_navigation", 0x1819_u32),
|
||||||
|
("org.bluetooth.service.next_dst_change", 0x1807_u32),
|
||||||
|
("org.bluetooth.service.object_transfer", 0x1825_u32),
|
||||||
|
("org.bluetooth.service.phone_alert_status", 0x180e_u32),
|
||||||
|
("org.bluetooth.service.pulse_oximeter", 0x1822_u32),
|
||||||
|
("org.bluetooth.service.reference_time_update", 0x1806_u32),
|
||||||
|
("org.bluetooth.service.running_speed_and_cadence", 0x1814_u32),
|
||||||
|
("org.bluetooth.service.scan_parameters", 0x1813_u32),
|
||||||
|
("org.bluetooth.service.transport_discovery", 0x1824),
|
||||||
|
("org.bluetooth.service.tx_power", 0x1804_u32),
|
||||||
|
("org.bluetooth.service.user_data", 0x181c_u32),
|
||||||
|
("org.bluetooth.service.weight_scale", 0x181d_u32),
|
||||||
];
|
];
|
||||||
|
|
||||||
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
|
||||||
//TODO(zakorgy) create all the characteristics
|
|
||||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||||
|
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.characteristic.aerobic_heart_rate_lower_limit", 0x2a7e_u32),
|
("org.bluetooth.characteristic.aerobic_heart_rate_lower_limit", 0x2a7e_u32),
|
||||||
("org.bluetooth.characteristic.aerobic_heart_rate_upper_limit", 0x2a84_u32),
|
("org.bluetooth.characteristic.aerobic_heart_rate_upper_limit", 0x2a84_u32),
|
||||||
("org.bluetooth.characteristic.battery_level", 0x2a19_u32)
|
("org.bluetooth.characteristic.aerobic_threshold", 0x2a7f_u32),
|
||||||
|
("org.bluetooth.characteristic.age", 0x2a80_u32),
|
||||||
|
("org.bluetooth.characteristic.aggregate", 0x2a5a_u32),
|
||||||
|
("org.bluetooth.characteristic.alert_category_id", 0x2a43_u32),
|
||||||
|
("org.bluetooth.characteristic.alert_category_id_bit_mask", 0x2a42_u32),
|
||||||
|
("org.bluetooth.characteristic.alert_level", 0x2a06_u32),
|
||||||
|
("org.bluetooth.characteristic.alert_notification_control_point", 0x2a44_u32),
|
||||||
|
("org.bluetooth.characteristic.alert_status", 0x2a3f_u32),
|
||||||
|
("org.bluetooth.characteristic.altitude", 0x2ab3_u32),
|
||||||
|
("org.bluetooth.characteristic.anaerobic_heart_rate_lower_limit", 0x2a81_u32),
|
||||||
|
("org.bluetooth.characteristic.anaerobic_heart_rate_upper_limit", 0x2a82_u32),
|
||||||
|
("org.bluetooth.characteristic.anaerobic_threshold", 0x2a83_u32),
|
||||||
|
("org.bluetooth.characteristic.analog", 0x2a58_u32),
|
||||||
|
("org.bluetooth.characteristic.apparent_wind_direction", 0x2a73_u32),
|
||||||
|
("org.bluetooth.characteristic.apparent_wind_speed", 0x2a72_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.appearance", 0x2a01_u32),
|
||||||
|
("org.bluetooth.characteristic.barometric_pressure_trend", 0x2aa3_u32),
|
||||||
|
("org.bluetooth.characteristic.battery_level", 0x2a19_u32),
|
||||||
|
("org.bluetooth.characteristic.blood_pressure_feature", 0x2a49_u32),
|
||||||
|
("org.bluetooth.characteristic.blood_pressure_measurement", 0x2a35_u32),
|
||||||
|
("org.bluetooth.characteristic.body_composition_feature", 0x2a9b_u32),
|
||||||
|
("org.bluetooth.characteristic.body_composition_measurement", 0x2a9c_u32),
|
||||||
|
("org.bluetooth.characteristic.body_sensor_location", 0x2a38_u32),
|
||||||
|
("org.bluetooth.characteristic.bond_management_control_point", 0x2aa4_u32),
|
||||||
|
("org.bluetooth.characteristic.bond_management_feature", 0x2aa5_u32),
|
||||||
|
("org.bluetooth.characteristic.boot_keyboard_input_report", 0x2a22_u32),
|
||||||
|
("org.bluetooth.characteristic.boot_keyboard_output_report", 0x2a32_u32),
|
||||||
|
("org.bluetooth.characteristic.boot_mouse_input_report", 0x2a33_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.central_address_resolution_support", 0x2aa6_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_feature", 0x2aa8_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_measurement", 0x2aa7_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_session_run_time", 0x2aab_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_session_start_time", 0x2aaa_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_specific_ops_control_point", 0x2aac_u32),
|
||||||
|
("org.bluetooth.characteristic.cgm_status", 0x2aa9_u32),
|
||||||
|
("org.bluetooth.characteristic.csc_feature", 0x2a5c_u32),
|
||||||
|
("org.bluetooth.characteristic.csc_measurement", 0x2a5b_u32),
|
||||||
|
("org.bluetooth.characteristic.current_time", 0x2a2b_u32),
|
||||||
|
("org.bluetooth.characteristic.cycling_power_control_point", 0x2a66_u32),
|
||||||
|
("org.bluetooth.characteristic.cycling_power_feature", 0x2a65_u32),
|
||||||
|
("org.bluetooth.characteristic.cycling_power_measurement", 0x2a63_u32),
|
||||||
|
("org.bluetooth.characteristic.cycling_power_vector", 0x2a64_u32),
|
||||||
|
("org.bluetooth.characteristic.database_change_increment", 0x2a99_u32),
|
||||||
|
("org.bluetooth.characteristic.date_of_birth", 0x2a85_u32),
|
||||||
|
("org.bluetooth.characteristic.date_of_threshold_assessment", 0x2a86_u32),
|
||||||
|
("org.bluetooth.characteristic.date_time", 0x2a08_u32),
|
||||||
|
("org.bluetooth.characteristic.day_date_time", 0x2a0a_u32),
|
||||||
|
("org.bluetooth.characteristic.day_of_week", 0x2a09_u32),
|
||||||
|
("org.bluetooth.characteristic.descriptor_value_changed", 0x2a7d_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.device_name", 0x2a00_u32),
|
||||||
|
("org.bluetooth.characteristic.dew_point", 0x2a7b_u32),
|
||||||
|
("org.bluetooth.characteristic.digital", 0x2a56_u32),
|
||||||
|
("org.bluetooth.characteristic.dst_offset", 0x2a0d_u32),
|
||||||
|
("org.bluetooth.characteristic.elevation", 0x2a6c_u32),
|
||||||
|
("org.bluetooth.characteristic.email_address", 0x2a87_u32),
|
||||||
|
("org.bluetooth.characteristic.exact_time_256", 0x2a0c_u32),
|
||||||
|
("org.bluetooth.characteristic.fat_burn_heart_rate_lower_limit", 0x2a88_u32),
|
||||||
|
("org.bluetooth.characteristic.fat_burn_heart_rate_upper_limit", 0x2a89_u32),
|
||||||
|
("org.bluetooth.characteristic.firmware_revision_string", 0x2a26_u32),
|
||||||
|
("org.bluetooth.characteristic.first_name", 0x2a8a_u32),
|
||||||
|
("org.bluetooth.characteristic.five_zone_heart_rate_limits", 0x2a8b_u32),
|
||||||
|
("org.bluetooth.characteristic.floor_number", 0x2ab2_u32),
|
||||||
|
("org.bluetooth.characteristic.gender", 0x2a8c_u32),
|
||||||
|
("org.bluetooth.characteristic.glucose_feature", 0x2a51_u32),
|
||||||
|
("org.bluetooth.characteristic.glucose_measurement", 0x2a18_u32),
|
||||||
|
("org.bluetooth.characteristic.glucose_measurement_context", 0x2a34_u32),
|
||||||
|
("org.bluetooth.characteristic.gust_factor", 0x2a74_u32),
|
||||||
|
("org.bluetooth.characteristic.hardware_revision_string", 0x2a27_u32),
|
||||||
|
("org.bluetooth.characteristic.heart_rate_control_point", 0x2a39_u32),
|
||||||
|
("org.bluetooth.characteristic.heart_rate_max", 0x2a8d_u32),
|
||||||
|
("org.bluetooth.characteristic.heart_rate_measurement", 0x2a37_u32),
|
||||||
|
("org.bluetooth.characteristic.heat_index", 0x2a7a_u32),
|
||||||
|
("org.bluetooth.characteristic.height", 0x2a8e_u32),
|
||||||
|
("org.bluetooth.characteristic.hid_control_point", 0x2a4c_u32),
|
||||||
|
("org.bluetooth.characteristic.hid_information", 0x2a4a_u32),
|
||||||
|
("org.bluetooth.characteristic.hip_circumference", 0x2a8f_u32),
|
||||||
|
("org.bluetooth.characteristic.http_control_point", 0x2aba_u32),
|
||||||
|
("org.bluetooth.characteristic.http_entity_body", 0x2ab9_u32),
|
||||||
|
("org.bluetooth.characteristic.http_headers", 0x2ab7_u32),
|
||||||
|
("org.bluetooth.characteristic.http_status_code", 0x2ab8_u32),
|
||||||
|
("org.bluetooth.characteristic.https_security", 0x2abb_u32),
|
||||||
|
("org.bluetooth.characteristic.humidity", 0x2a6f_u32),
|
||||||
|
("org.bluetooth.characteristic.ieee_11073-20601_regulatory_certification_data_list", 0x2a2a_u32),
|
||||||
|
("org.bluetooth.characteristic.indoor_positioning_configuration", 0x2aad_u32),
|
||||||
|
("org.bluetooth.characteristic.intermediate_cuff_pressure", 0x2a36_u32),
|
||||||
|
("org.bluetooth.characteristic.intermediate_temperature", 0x2a1e_u32),
|
||||||
|
("org.bluetooth.characteristic.irradiance", 0x2a77_u32),
|
||||||
|
("org.bluetooth.characteristic.language", 0x2aa2_u32),
|
||||||
|
("org.bluetooth.characteristic.last_name", 0x2a90_u32),
|
||||||
|
("org.bluetooth.characteristic.latitude", 0x2aae_u32),
|
||||||
|
("org.bluetooth.characteristic.ln_control_point", 0x2a6b_u32),
|
||||||
|
("org.bluetooth.characteristic.ln_feature", 0x2a6a_u32),
|
||||||
|
("org.bluetooth.characteristic.local_east_coordinate.xml", 0x2ab1_u32),
|
||||||
|
("org.bluetooth.characteristic.local_north_coordinate", 0x2ab0_u32),
|
||||||
|
("org.bluetooth.characteristic.local_time_information", 0x2a0f_u32),
|
||||||
|
("org.bluetooth.characteristic.location_and_speed", 0x2a67_u32),
|
||||||
|
("org.bluetooth.characteristic.location_name", 0x2ab5_u32),
|
||||||
|
("org.bluetooth.characteristic.longitude", 0x2aaf_u32),
|
||||||
|
("org.bluetooth.characteristic.magnetic_declination", 0x2a2c_u32),
|
||||||
|
("org.bluetooth.characteristic.magnetic_flux_density_2d", 0x2aa0_u32),
|
||||||
|
("org.bluetooth.characteristic.magnetic_flux_density_3d", 0x2aa1_u32),
|
||||||
|
("org.bluetooth.characteristic.manufacturer_name_string", 0x2a29_u32),
|
||||||
|
("org.bluetooth.characteristic.maximum_recommended_heart_rate", 0x2a91_u32),
|
||||||
|
("org.bluetooth.characteristic.measurement_interval", 0x2a21_u32),
|
||||||
|
("org.bluetooth.characteristic.model_number_string", 0x2a24_u32),
|
||||||
|
("org.bluetooth.characteristic.navigation", 0x2a68_u32),
|
||||||
|
("org.bluetooth.characteristic.new_alert", 0x2a46_u32),
|
||||||
|
("org.bluetooth.characteristic.object_action_control_point", 0x2ac5_u32),
|
||||||
|
("org.bluetooth.characteristic.object_changed", 0x2ac8_u32),
|
||||||
|
("org.bluetooth.characteristic.object_first_created", 0x2ac1_u32),
|
||||||
|
("org.bluetooth.characteristic.object_id", 0x2ac3_u32),
|
||||||
|
("org.bluetooth.characteristic.object_last_modified", 0x2ac2_u32),
|
||||||
|
("org.bluetooth.characteristic.object_list_control_point", 0x2ac6_u32),
|
||||||
|
("org.bluetooth.characteristic.object_list_filter", 0x2ac7_u32),
|
||||||
|
("org.bluetooth.characteristic.object_name", 0x2abe_u32),
|
||||||
|
("org.bluetooth.characteristic.object_properties", 0x2ac4_u32),
|
||||||
|
("org.bluetooth.characteristic.object_size", 0x2ac0_u32),
|
||||||
|
("org.bluetooth.characteristic.object_type", 0x2abf_u32),
|
||||||
|
("org.bluetooth.characteristic.ots_feature", 0x2abd_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters", 0x2a04_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.peripheral_privacy_flag", 0x2a02_u32),
|
||||||
|
("org.bluetooth.characteristic.plx_continuous_measurement", 0x2a5f_u32),
|
||||||
|
("org.bluetooth.characteristic.plx_features", 0x2a60_u32),
|
||||||
|
("org.bluetooth.characteristic.plx_spot_check_measurement", 0x2a5e_u32),
|
||||||
|
("org.bluetooth.characteristic.pnp_id", 0x2a50_u32),
|
||||||
|
("org.bluetooth.characteristic.pollen_concentration", 0x2a75_u32),
|
||||||
|
("org.bluetooth.characteristic.position_quality", 0x2a69_u32),
|
||||||
|
("org.bluetooth.characteristic.pressure", 0x2a6d_u32),
|
||||||
|
("org.bluetooth.characteristic.protocol_mode", 0x2a4e_u32),
|
||||||
|
("org.bluetooth.characteristic.rainfall", 0x2a78_u32),
|
||||||
|
("org.bluetooth.characteristic.gap.reconnection_address", 0x2a03_u32),
|
||||||
|
("org.bluetooth.characteristic.record_access_control_point", 0x2a52_u32),
|
||||||
|
("org.bluetooth.characteristic.reference_time_information", 0x2a14_u32),
|
||||||
|
("org.bluetooth.characteristic.report", 0x2a4d_u32),
|
||||||
|
("org.bluetooth.characteristic.report_map", 0x2a4b_u32),
|
||||||
|
("org.bluetooth.characteristic.resting_heart_rate", 0x2a92_u32),
|
||||||
|
("org.bluetooth.characteristic.ringer_control_point", 0x2a40_u32),
|
||||||
|
("org.bluetooth.characteristic.ringer_setting", 0x2a41_u32),
|
||||||
|
("org.bluetooth.characteristic.rsc_feature", 0x2a54_u32),
|
||||||
|
("org.bluetooth.characteristic.rsc_measurement", 0x2a53_u32),
|
||||||
|
("org.bluetooth.characteristic.sc_control_point", 0x2a55_u32),
|
||||||
|
("org.bluetooth.characteristic.scan_interval_window", 0x2a4f_u32),
|
||||||
|
("org.bluetooth.characteristic.scan_refresh", 0x2a31_u32),
|
||||||
|
("org.bluetooth.characteristic.sensor_location", 0x2a5d_u32),
|
||||||
|
("org.bluetooth.characteristic.serial_number_string", 0x2a25_u32),
|
||||||
|
("org.bluetooth.characteristic.gatt.service_changed", 0x2a05_u32),
|
||||||
|
("org.bluetooth.characteristic.software_revision_string", 0x2a28_u32),
|
||||||
|
("org.bluetooth.characteristic.sport_type_for_aerobic_and_anaerobic_thresholds", 0x2a93_u32),
|
||||||
|
("org.bluetooth.characteristic.supported_new_alert_category", 0x2a47_u32),
|
||||||
|
("org.bluetooth.characteristic.supported_unread_alert_category", 0x2a48_u32),
|
||||||
|
("org.bluetooth.characteristic.system_id", 0x2a23_u32),
|
||||||
|
("org.bluetooth.characteristic.tds_control_point", 0x2abc_u32),
|
||||||
|
("org.bluetooth.characteristic.temperature", 0x2a6e_u32),
|
||||||
|
("org.bluetooth.characteristic.temperature_measurement", 0x2a1c_u32),
|
||||||
|
("org.bluetooth.characteristic.temperature_type", 0x2a1d_u32),
|
||||||
|
("org.bluetooth.characteristic.three_zone_heart_rate_limits", 0x2a94_u32),
|
||||||
|
("org.bluetooth.characteristic.time_accuracy", 0x2a12_u32),
|
||||||
|
("org.bluetooth.characteristic.time_source", 0x2a13_u32),
|
||||||
|
("org.bluetooth.characteristic.time_update_control_point", 0x2a16_u32),
|
||||||
|
("org.bluetooth.characteristic.time_update_state", 0x2a17_u32),
|
||||||
|
("org.bluetooth.characteristic.time_with_dst", 0x2a11_u32),
|
||||||
|
("org.bluetooth.characteristic.time_zone", 0x2a0e_u32),
|
||||||
|
("org.bluetooth.characteristic.true_wind_direction", 0x2a71_u32),
|
||||||
|
("org.bluetooth.characteristic.true_wind_speed", 0x2a70_u32),
|
||||||
|
("org.bluetooth.characteristic.two_zone_heart_rate_limit", 0x2a95_u32),
|
||||||
|
("org.bluetooth.characteristic.tx_power_level", 0x2a07_u32),
|
||||||
|
("org.bluetooth.characteristic.uncertainty", 0x2ab4_u32),
|
||||||
|
("org.bluetooth.characteristic.unread_alert_status", 0x2a45_u32),
|
||||||
|
("org.bluetooth.characteristic.uri", 0x2ab6_u32),
|
||||||
|
("org.bluetooth.characteristic.user_control_point", 0x2a9f_u32),
|
||||||
|
("org.bluetooth.characteristic.user_index", 0x2a9a_u32),
|
||||||
|
("org.bluetooth.characteristic.uv_index", 0x2a76_u32),
|
||||||
|
("org.bluetooth.characteristic.vo2_max", 0x2a96_u32),
|
||||||
|
("org.bluetooth.characteristic.waist_circumference", 0x2a97_u32),
|
||||||
|
("org.bluetooth.characteristic.weight", 0x2a98_u32),
|
||||||
|
("org.bluetooth.characteristic.weight_measurement", 0x2a9d_u32),
|
||||||
|
("org.bluetooth.characteristic.weight_scale_feature", 0x2a9e_u32),
|
||||||
|
("org.bluetooth.characteristic.wind_chill", 0x2a79_u32),
|
||||||
];
|
];
|
||||||
|
|
||||||
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[
|
|
||||||
//TODO(zakorgy) create all the descriptors
|
|
||||||
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
//https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx
|
||||||
|
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, u32)] = &[
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_extended_properties", 0x2900_u32),
|
("org.bluetooth.descriptor.gatt.characteristic_extended_properties", 0x2900_u32),
|
||||||
("org.bluetooth.descriptor.gatt.characteristic_user_description", 0x2901_u32)
|
("org.bluetooth.descriptor.gatt.characteristic_user_description", 0x2901_u32),
|
||||||
|
("org.bluetooth.descriptor.gatt.client_characteristic_configuration", 0x2902_u32),
|
||||||
|
("org.bluetooth.descriptor.gatt.server_characteristic_configuration", 0x2903_u32),
|
||||||
|
("org.bluetooth.descriptor.gatt.characteristic_presentation_format", 0x2904_u32),
|
||||||
|
("org.bluetooth.descriptor.gatt.characteristic_aggregate_format", 0x2905_u32),
|
||||||
|
("org.bluetooth.descriptor.valid_range", 0x2906_u32),
|
||||||
|
("org.bluetooth.descriptor.external_report_reference", 0x2907_u32),
|
||||||
|
("org.bluetooth.descriptor.report_reference", 0x2908_u32),
|
||||||
|
("org.bluetooth.descriptor.number_of_digitals", 0x2909_u32),
|
||||||
|
("org.bluetooth.descriptor.value_trigger_setting", 0x290a_u32),
|
||||||
|
("org.bluetooth.descriptor.es_configuration", 0x290b_u32),
|
||||||
|
("org.bluetooth.descriptor.es_measurement", 0x290c_u32),
|
||||||
|
("org.bluetooth.descriptor.es_trigger_setting", 0x290d_u32),
|
||||||
|
("org.bluetooth.descriptor.time_trigger_setting", 0x290e_u32),
|
||||||
];
|
];
|
||||||
|
|
||||||
const BASE_UUID: &'static str = "-0000-1000-8000-00805f9b34fb";
|
const BASE_UUID: &'static str = "-0000-1000-8000-00805f9b34fb";
|
||||||
|
@ -55,9 +277,7 @@ impl BluetoothUUID {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice
|
||||||
pub fn GetService(globalref: GlobalRef,
|
pub fn GetService(globalref: GlobalRef, name: BluetoothServiceUUID) -> Fallible<UUID> {
|
||||||
name: StringOrUnsignedLong)
|
|
||||||
-> Fallible<UUID> {
|
|
||||||
BluetoothUUID::resolve_uuid_name(globalref,
|
BluetoothUUID::resolve_uuid_name(globalref,
|
||||||
name,
|
name,
|
||||||
BLUETOOTH_ASSIGNED_SERVICES,
|
BLUETOOTH_ASSIGNED_SERVICES,
|
||||||
|
@ -65,9 +285,7 @@ impl BluetoothUUID {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getcharacteristic
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getcharacteristic
|
||||||
pub fn GetCharacteristic(globalref: GlobalRef,
|
pub fn GetCharacteristic(globalref: GlobalRef, name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
|
||||||
name: StringOrUnsignedLong)
|
|
||||||
-> Fallible<UUID> {
|
|
||||||
BluetoothUUID::resolve_uuid_name(globalref,
|
BluetoothUUID::resolve_uuid_name(globalref,
|
||||||
name,
|
name,
|
||||||
BLUETOOTH_ASSIGNED_CHARCTERISTICS,
|
BLUETOOTH_ASSIGNED_CHARCTERISTICS,
|
||||||
|
@ -75,9 +293,7 @@ impl BluetoothUUID {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getdescriptor
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getdescriptor
|
||||||
pub fn GetDescriptor(globalref: GlobalRef,
|
pub fn GetDescriptor(globalref: GlobalRef, name: BluetoothDescriptorUUID) -> Fallible<UUID> {
|
||||||
name: StringOrUnsignedLong)
|
|
||||||
-> Fallible<UUID> {
|
|
||||||
BluetoothUUID::resolve_uuid_name(globalref,
|
BluetoothUUID::resolve_uuid_name(globalref,
|
||||||
name,
|
name,
|
||||||
BLUETOOTH_ASSIGNED_DESCRIPTORS,
|
BLUETOOTH_ASSIGNED_DESCRIPTORS,
|
||||||
|
@ -103,8 +319,7 @@ impl BluetoothUUID {
|
||||||
} else {
|
} else {
|
||||||
// Step 3
|
// Step 3
|
||||||
let concatenated = format!("{}.{}", prefix, dstring);
|
let concatenated = format!("{}.{}", prefix, dstring);
|
||||||
let is_in_table = assigned_numbers_table.iter()
|
let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated);
|
||||||
.find(|p| p.0 == concatenated);
|
|
||||||
match is_in_table {
|
match is_in_table {
|
||||||
Some(&(_, alias)) => Ok(BluetoothUUID::CanonicalUUID(globalref, alias)),
|
Some(&(_, alias)) => Ok(BluetoothUUID::CanonicalUUID(globalref, alias)),
|
||||||
None => Err(Syntax),
|
None => Err(Syntax),
|
||||||
|
@ -114,3 +329,12 @@ impl BluetoothUUID {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for StringOrUnsignedLong {
|
||||||
|
fn clone(&self) -> StringOrUnsignedLong {
|
||||||
|
match self {
|
||||||
|
&StringOrUnsignedLong::String(ref s) => StringOrUnsignedLong::String(s.clone()),
|
||||||
|
&StringOrUnsignedLong::UnsignedLong(ul) => StringOrUnsignedLong::UnsignedLong(ul),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,10 +4,22 @@
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
|
// https://webbluetoothcg.github.io/web-bluetooth/#bluetooth
|
||||||
|
|
||||||
|
dictionary BluetoothScanFilter {
|
||||||
|
sequence<BluetoothServiceUUID> services;
|
||||||
|
DOMString name;
|
||||||
|
DOMString namePrefix;
|
||||||
|
};
|
||||||
|
|
||||||
|
dictionary RequestDeviceOptions {
|
||||||
|
required sequence<BluetoothScanFilter> filters;
|
||||||
|
sequence<BluetoothServiceUUID> optionalServices /*= []*/;
|
||||||
|
};
|
||||||
|
|
||||||
[Pref="dom.bluetooth.enabled"]
|
[Pref="dom.bluetooth.enabled"]
|
||||||
interface Bluetooth {
|
interface Bluetooth {
|
||||||
// Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
|
// Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
|
||||||
BluetoothDevice? requestDevice(/*RequestDeviceOptions options*/);
|
[Throws]
|
||||||
|
BluetoothDevice requestDevice(RequestDeviceOptions options);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bluetooth implements EventTarget;
|
// Bluetooth implements EventTarget;
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
// Allocation authorities for Vendor IDs:
|
// Allocation authorities for Vendor IDs:
|
||||||
enum VendorIDSource {
|
enum VendorIDSource {
|
||||||
"bluetooth",
|
"bluetooth",
|
||||||
"usb"
|
"usb",
|
||||||
|
"unknown"
|
||||||
};
|
};
|
||||||
|
|
||||||
[Pref="dom.bluetooth.enabled"]
|
[Pref="dom.bluetooth.enabled"]
|
||||||
|
|
|
@ -10,12 +10,18 @@ interface BluetoothRemoteGATTCharacteristic {
|
||||||
readonly attribute DOMString uuid;
|
readonly attribute DOMString uuid;
|
||||||
readonly attribute BluetoothCharacteristicProperties properties;
|
readonly attribute BluetoothCharacteristicProperties properties;
|
||||||
readonly attribute ByteString? value;
|
readonly attribute ByteString? value;
|
||||||
BluetoothRemoteGATTDescriptor? getDescriptor(/*BluetoothDescriptorUUID descriptor*/);
|
[Throws]
|
||||||
|
BluetoothRemoteGATTDescriptor getDescriptor(BluetoothDescriptorUUID descriptor);
|
||||||
|
[Throws]
|
||||||
|
sequence<BluetoothRemoteGATTDescriptor> getDescriptors(optional BluetoothDescriptorUUID descriptor);
|
||||||
//Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
|
//Promise<BluetoothRemoteGATTDescriptor> getDescriptor(BluetoothDescriptorUUID descriptor);
|
||||||
//Promise<sequence<BluetoothRemoteGATTDescriptor>>
|
//Promise<sequence<BluetoothRemoteGATTDescriptor>>
|
||||||
//getDescriptors(optional BluetoothDescriptorUUID descriptor);
|
//getDescriptors(optional BluetoothDescriptorUUID descriptor);
|
||||||
//Promise<DataView> readValue();
|
[Throws]
|
||||||
ByteString readValue();
|
ByteString readValue();
|
||||||
|
//Promise<DataView> readValue();
|
||||||
|
[Throws]
|
||||||
|
void writeValue(sequence<octet> value);
|
||||||
//Promise<void> writeValue(BufferSource value);
|
//Promise<void> writeValue(BufferSource value);
|
||||||
//Promise<void> startNotifications();
|
//Promise<void> startNotifications();
|
||||||
//Promise<void> stopNotifications();
|
//Promise<void> stopNotifications();
|
||||||
|
|
|
@ -9,8 +9,10 @@ interface BluetoothRemoteGATTDescriptor {
|
||||||
readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
|
readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
|
||||||
readonly attribute DOMString uuid;
|
readonly attribute DOMString uuid;
|
||||||
readonly attribute ByteString? value;
|
readonly attribute ByteString? value;
|
||||||
|
[Throws]
|
||||||
ByteString readValue();
|
ByteString readValue();
|
||||||
//Promise<DataView> readValue();
|
//Promise<DataView> readValue();
|
||||||
|
[Throws]
|
||||||
|
void writeValue(sequence<octet> value);
|
||||||
//Promise<void> writeValue(BufferSource value);
|
//Promise<void> writeValue(BufferSource value);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,9 +8,14 @@
|
||||||
interface BluetoothRemoteGATTServer {
|
interface BluetoothRemoteGATTServer {
|
||||||
readonly attribute BluetoothDevice device;
|
readonly attribute BluetoothDevice device;
|
||||||
readonly attribute boolean connected;
|
readonly attribute boolean connected;
|
||||||
|
[Throws]
|
||||||
BluetoothRemoteGATTServer connect();
|
BluetoothRemoteGATTServer connect();
|
||||||
|
[Throws]
|
||||||
void disconnect();
|
void disconnect();
|
||||||
BluetoothRemoteGATTService? getPrimaryService();
|
[Throws]
|
||||||
|
BluetoothRemoteGATTService getPrimaryService(BluetoothServiceUUID service);
|
||||||
|
[Throws]
|
||||||
|
sequence<BluetoothRemoteGATTService> getPrimaryServices(optional BluetoothServiceUUID service);
|
||||||
//Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service);
|
//Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service);
|
||||||
//Promise<sequence<BluetoothRemoteGATTService>>getPrimaryServices(optional BluetoothServiceUUID service);
|
//Promise<sequence<BluetoothRemoteGATTService>>getPrimaryServices(optional BluetoothServiceUUID service);
|
||||||
//Promise<BluetoothRemoteGATTServer> connect();
|
//Promise<BluetoothRemoteGATTServer> connect();
|
||||||
|
|
|
@ -9,7 +9,11 @@ interface BluetoothRemoteGATTService {
|
||||||
readonly attribute BluetoothDevice device;
|
readonly attribute BluetoothDevice device;
|
||||||
readonly attribute DOMString uuid;
|
readonly attribute DOMString uuid;
|
||||||
readonly attribute boolean isPrimary;
|
readonly attribute boolean isPrimary;
|
||||||
BluetoothRemoteGATTCharacteristic? getCharacteristic(/*DOMString characteristic*/);
|
[Throws]
|
||||||
|
BluetoothRemoteGATTCharacteristic getCharacteristic(BluetoothCharacteristicUUID characteristic);
|
||||||
|
[Throws]
|
||||||
|
sequence<BluetoothRemoteGATTCharacteristic> getCharacteristics
|
||||||
|
(optional BluetoothCharacteristicUUID characteristic);
|
||||||
//Promise<BluetoothRemoteGATTCharacteristic>getCharacteristic(BluetoothCharacteristicUUID characteristic);
|
//Promise<BluetoothRemoteGATTCharacteristic>getCharacteristic(BluetoothCharacteristicUUID characteristic);
|
||||||
//Promise<sequence<BluetoothRemoteGATTCharacteristic>>
|
//Promise<sequence<BluetoothRemoteGATTCharacteristic>>
|
||||||
//getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
|
//getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
|
||||||
|
|
|
@ -47,6 +47,7 @@ use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId}
|
||||||
use msg::constellation_msg::{WindowSizeData, WindowSizeType};
|
use msg::constellation_msg::{WindowSizeData, WindowSizeType};
|
||||||
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||||
use net_traits::ResourceThread;
|
use net_traits::ResourceThread;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
|
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
|
||||||
use net_traits::storage_thread::{StorageThread, StorageType};
|
use net_traits::storage_thread::{StorageThread, StorageType};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
@ -212,6 +213,10 @@ pub struct Window {
|
||||||
#[ignore_heap_size_of = "channels are hard"]
|
#[ignore_heap_size_of = "channels are hard"]
|
||||||
resource_thread: Arc<ResourceThread>,
|
resource_thread: Arc<ResourceThread>,
|
||||||
|
|
||||||
|
/// A handle for communicating messages to the bluetooth thread.
|
||||||
|
#[ignore_heap_size_of = "channels are hard"]
|
||||||
|
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
|
|
||||||
/// A handle for communicating messages to the storage thread.
|
/// A handle for communicating messages to the storage thread.
|
||||||
#[ignore_heap_size_of = "channels are hard"]
|
#[ignore_heap_size_of = "channels are hard"]
|
||||||
storage_thread: StorageThread,
|
storage_thread: StorageThread,
|
||||||
|
@ -334,6 +339,10 @@ impl Window {
|
||||||
&*self.page
|
&*self.page
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||||
|
self.bluetooth_thread.clone()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn storage_thread(&self) -> StorageThread {
|
pub fn storage_thread(&self) -> StorageThread {
|
||||||
self.storage_thread.clone()
|
self.storage_thread.clone()
|
||||||
}
|
}
|
||||||
|
@ -1407,6 +1416,7 @@ impl Window {
|
||||||
compositor: IpcSender<ScriptToCompositorMsg>,
|
compositor: IpcSender<ScriptToCompositorMsg>,
|
||||||
image_cache_thread: ImageCacheThread,
|
image_cache_thread: ImageCacheThread,
|
||||||
resource_thread: Arc<ResourceThread>,
|
resource_thread: Arc<ResourceThread>,
|
||||||
|
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
storage_thread: StorageThread,
|
storage_thread: StorageThread,
|
||||||
mem_profiler_chan: mem::ProfilerChan,
|
mem_profiler_chan: mem::ProfilerChan,
|
||||||
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||||
|
@ -1462,6 +1472,7 @@ impl Window {
|
||||||
dom_static: GlobalStaticData::new(),
|
dom_static: GlobalStaticData::new(),
|
||||||
js_runtime: DOMRefCell::new(Some(runtime.clone())),
|
js_runtime: DOMRefCell::new(Some(runtime.clone())),
|
||||||
resource_thread: resource_thread,
|
resource_thread: resource_thread,
|
||||||
|
bluetooth_thread: bluetooth_thread,
|
||||||
storage_thread: storage_thread,
|
storage_thread: storage_thread,
|
||||||
constellation_chan: constellation_chan,
|
constellation_chan: constellation_chan,
|
||||||
page_clip_rect: Cell::new(MAX_RECT),
|
page_clip_rect: Cell::new(MAX_RECT),
|
||||||
|
|
|
@ -64,6 +64,7 @@ use msg::constellation_msg::{PipelineId, PipelineNamespace};
|
||||||
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
||||||
use msg::webdriver_msg::WebDriverScriptCommand;
|
use msg::webdriver_msg::WebDriverScriptCommand;
|
||||||
use net_traits::LoadData as NetLoadData;
|
use net_traits::LoadData as NetLoadData;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||||
use net_traits::storage_thread::StorageThread;
|
use net_traits::storage_thread::StorageThread;
|
||||||
use net_traits::{AsyncResponseTarget, ControlMsg, LoadConsumer, LoadContext, Metadata, ResourceThread};
|
use net_traits::{AsyncResponseTarget, ControlMsg, LoadConsumer, LoadContext, Metadata, ResourceThread};
|
||||||
|
@ -310,6 +311,8 @@ pub struct ScriptThread {
|
||||||
/// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if
|
/// A handle to the resource thread. This is an `Arc` to avoid running out of file descriptors if
|
||||||
/// there are many iframes.
|
/// there are many iframes.
|
||||||
resource_thread: Arc<ResourceThread>,
|
resource_thread: Arc<ResourceThread>,
|
||||||
|
/// A handle to the bluetooth thread.
|
||||||
|
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
/// A handle to the storage thread.
|
/// A handle to the storage thread.
|
||||||
storage_thread: StorageThread,
|
storage_thread: StorageThread,
|
||||||
|
|
||||||
|
@ -554,6 +557,7 @@ impl ScriptThread {
|
||||||
image_cache_port: image_cache_port,
|
image_cache_port: image_cache_port,
|
||||||
|
|
||||||
resource_thread: Arc::new(state.resource_thread),
|
resource_thread: Arc::new(state.resource_thread),
|
||||||
|
bluetooth_thread: state.bluetooth_thread,
|
||||||
storage_thread: state.storage_thread,
|
storage_thread: state.storage_thread,
|
||||||
|
|
||||||
port: port,
|
port: port,
|
||||||
|
@ -1496,6 +1500,7 @@ impl ScriptThread {
|
||||||
self.compositor.borrow_mut().clone(),
|
self.compositor.borrow_mut().clone(),
|
||||||
self.image_cache_thread.clone(),
|
self.image_cache_thread.clone(),
|
||||||
self.resource_thread.clone(),
|
self.resource_thread.clone(),
|
||||||
|
self.bluetooth_thread.clone(),
|
||||||
self.storage_thread.clone(),
|
self.storage_thread.clone(),
|
||||||
self.mem_profiler_chan.clone(),
|
self.mem_profiler_chan.clone(),
|
||||||
self.devtools_chan.clone(),
|
self.devtools_chan.clone(),
|
||||||
|
|
|
@ -46,6 +46,7 @@ use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
|
||||||
use msg::constellation_msg::{PipelineNamespaceId, SubpageId};
|
use msg::constellation_msg::{PipelineNamespaceId, SubpageId};
|
||||||
use msg::webdriver_msg::WebDriverScriptCommand;
|
use msg::webdriver_msg::WebDriverScriptCommand;
|
||||||
use net_traits::ResourceThread;
|
use net_traits::ResourceThread;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::image_cache_thread::ImageCacheThread;
|
use net_traits::image_cache_thread::ImageCacheThread;
|
||||||
use net_traits::response::HttpsState;
|
use net_traits::response::HttpsState;
|
||||||
use net_traits::storage_thread::StorageThread;
|
use net_traits::storage_thread::StorageThread;
|
||||||
|
@ -320,6 +321,8 @@ pub struct InitialScriptState {
|
||||||
pub scheduler_chan: IpcSender<TimerEventRequest>,
|
pub scheduler_chan: IpcSender<TimerEventRequest>,
|
||||||
/// A channel to the resource manager thread.
|
/// A channel to the resource manager thread.
|
||||||
pub resource_thread: ResourceThread,
|
pub resource_thread: ResourceThread,
|
||||||
|
/// A channel to the bluetooth thread.
|
||||||
|
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||||
/// A channel to the storage thread.
|
/// A channel to the storage thread.
|
||||||
pub storage_thread: StorageThread,
|
pub storage_thread: StorageThread,
|
||||||
/// A channel to the image cache thread.
|
/// A channel to the image cache thread.
|
||||||
|
|
28
components/servo/Cargo.lock
generated
28
components/servo/Cargo.lock
generated
|
@ -167,6 +167,15 @@ name = "block"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blurz"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"dbus 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "0.3.20"
|
version = "0.3.20"
|
||||||
|
@ -414,6 +423,15 @@ dependencies = [
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "debug_unreachable"
|
name = "debug_unreachable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -430,6 +448,14 @@ dependencies = [
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "device"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "git+https://github.com/servo/devices#eeac5abfd548b63dcc48873261609922351551e1"
|
||||||
|
dependencies = [
|
||||||
|
"blurz 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "devtools"
|
name = "devtools"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -1305,8 +1331,10 @@ dependencies = [
|
||||||
name = "net"
|
name = "net"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
||||||
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"device 0.0.1 (git+https://github.com/servo/devices)",
|
||||||
"devtools_traits 0.0.1",
|
"devtools_traits 0.0.1",
|
||||||
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -71,9 +71,11 @@ use compositing::{CompositorProxy, CompositorThread, Constellation};
|
||||||
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
|
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
|
||||||
use gfx::font_cache_thread::FontCacheThread;
|
use gfx::font_cache_thread::FontCacheThread;
|
||||||
use ipc_channel::ipc::{self, IpcSender};
|
use ipc_channel::ipc::{self, IpcSender};
|
||||||
|
use net::bluetooth_thread::BluetoothThreadFactory;
|
||||||
use net::image_cache_thread::new_image_cache_thread;
|
use net::image_cache_thread::new_image_cache_thread;
|
||||||
use net::resource_thread::new_resource_thread;
|
use net::resource_thread::new_resource_thread;
|
||||||
use net::storage_thread::StorageThreadFactory;
|
use net::storage_thread::StorageThreadFactory;
|
||||||
|
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||||
use net_traits::storage_thread::StorageThread;
|
use net_traits::storage_thread::StorageThread;
|
||||||
use profile::mem as profile_mem;
|
use profile::mem as profile_mem;
|
||||||
use profile::time as profile_time;
|
use profile::time as profile_time;
|
||||||
|
@ -208,6 +210,7 @@ fn create_constellation(opts: opts::Opts,
|
||||||
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
||||||
supports_clipboard: bool,
|
supports_clipboard: bool,
|
||||||
webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
|
webrender_api_sender: Option<webrender_traits::RenderApiSender>) -> Sender<ConstellationMsg> {
|
||||||
|
let bluetooth_thread: IpcSender<BluetoothMethodMsg> = BluetoothThreadFactory::new();
|
||||||
let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
|
let resource_thread = new_resource_thread(opts.user_agent.clone(), devtools_chan.clone());
|
||||||
let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
|
let image_cache_thread = new_image_cache_thread(resource_thread.clone(),
|
||||||
webrender_api_sender.as_ref().map(|wr| wr.create_api()));
|
webrender_api_sender.as_ref().map(|wr| wr.create_api()));
|
||||||
|
@ -218,6 +221,7 @@ fn create_constellation(opts: opts::Opts,
|
||||||
let initial_state = InitialConstellationState {
|
let initial_state = InitialConstellationState {
|
||||||
compositor_proxy: compositor_proxy,
|
compositor_proxy: compositor_proxy,
|
||||||
devtools_chan: devtools_chan,
|
devtools_chan: devtools_chan,
|
||||||
|
bluetooth_thread: bluetooth_thread,
|
||||||
image_cache_thread: image_cache_thread,
|
image_cache_thread: image_cache_thread,
|
||||||
font_cache_thread: font_cache_thread,
|
font_cache_thread: font_cache_thread,
|
||||||
resource_thread: resource_thread,
|
resource_thread: resource_thread,
|
||||||
|
|
28
ports/cef/Cargo.lock
generated
28
ports/cef/Cargo.lock
generated
|
@ -153,6 +153,15 @@ name = "block"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blurz"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"dbus 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "0.3.20"
|
version = "0.3.20"
|
||||||
|
@ -385,6 +394,15 @@ dependencies = [
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "debug_unreachable"
|
name = "debug_unreachable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -401,6 +419,14 @@ dependencies = [
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "device"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "git+https://github.com/servo/devices#eeac5abfd548b63dcc48873261609922351551e1"
|
||||||
|
dependencies = [
|
||||||
|
"blurz 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "devtools"
|
name = "devtools"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -1219,8 +1245,10 @@ dependencies = [
|
||||||
name = "net"
|
name = "net"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
||||||
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"device 0.0.1 (git+https://github.com/servo/devices)",
|
||||||
"devtools_traits 0.0.1",
|
"devtools_traits 0.0.1",
|
||||||
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
28
ports/gonk/Cargo.lock
generated
28
ports/gonk/Cargo.lock
generated
|
@ -146,6 +146,15 @@ name = "block"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blurz"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"dbus 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "0.3.20"
|
version = "0.3.20"
|
||||||
|
@ -378,6 +387,15 @@ dependencies = [
|
||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dbus"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "debug_unreachable"
|
name = "debug_unreachable"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
@ -394,6 +412,14 @@ dependencies = [
|
||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "device"
|
||||||
|
version = "0.0.1"
|
||||||
|
source = "git+https://github.com/servo/devices#eeac5abfd548b63dcc48873261609922351551e1"
|
||||||
|
dependencies = [
|
||||||
|
"blurz 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "devtools"
|
name = "devtools"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
|
@ -1202,8 +1228,10 @@ dependencies = [
|
||||||
name = "net"
|
name = "net"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bitflags 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
"brotli 0.3.20 (git+https://github.com/ende76/brotli-rs)",
|
||||||
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cookie 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"device 0.0.1 (git+https://github.com/servo/devices)",
|
||||||
"devtools_traits 0.0.1",
|
"devtools_traits 0.0.1",
|
||||||
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"hyper 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
61
tests/html/bluetooth_battery_level.html
Normal file
61
tests/html/bluetooth_battery_level.html
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Battery Level</title>
|
||||||
|
<body>
|
||||||
|
<input id="name" type="text" placeholder="Device Name">
|
||||||
|
<input id="namePrefix" type="text" placeholder="Device Name Prefix">
|
||||||
|
<button type="button" onclick="onButtonClick()">Get Bluetooth Device's Battery Level</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
function onButtonClick() {
|
||||||
|
clear();
|
||||||
|
var options = {filters: [{services: ['battery_service']}], optinalServices: []};
|
||||||
|
|
||||||
|
var filterName = document.getElementById('name').value;
|
||||||
|
if (filterName)
|
||||||
|
options.filters.push({name: filterName});
|
||||||
|
|
||||||
|
var filterNamePrefix = document.getElementById('namePrefix').value;
|
||||||
|
if (filterNamePrefix)
|
||||||
|
options.filters.push({namePrefix: filterNamePrefix});
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
var bluetooth = window.navigator.bluetooth;
|
||||||
|
var device = bluetooth.requestDevice(options);
|
||||||
|
|
||||||
|
log('Connecting to GATT Server on device...');
|
||||||
|
var server = device.gatt.connect();
|
||||||
|
|
||||||
|
log('Getting Battery Service...');
|
||||||
|
var service = server.getPrimaryService('battery_service');
|
||||||
|
|
||||||
|
log('Getting Battery Level Characteristic...');
|
||||||
|
var characteristic = service.getCharacteristic('battery_level');
|
||||||
|
|
||||||
|
log('Reading Battery Level...');
|
||||||
|
var value = AsciiToDecimal(characteristic.readValue());
|
||||||
|
log('> Battery Level is ' + value + '%');
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
function AsciiToDecimal(bytestr) {
|
||||||
|
var result = [];
|
||||||
|
for(i = 0; i < bytestr.length; i++) {
|
||||||
|
result[i] = bytestr[i].charCodeAt(0) ;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
69
tests/html/bluetooth_characteristic_info.html
Normal file
69
tests/html/bluetooth_characteristic_info.html
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Characteristic info</title>
|
||||||
|
<body>
|
||||||
|
<input id="service" type="text" autofocus placeholder="Bluetooth Service">
|
||||||
|
<input id="characteristic" type="text" autofocus placeholder="Bluetooth Characteristic">
|
||||||
|
<button type="button" onclick="onButtonClick()">Get Characteristic Info</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
function onButtonClick() {
|
||||||
|
clear();
|
||||||
|
var serviceUuid = document.getElementById('service').value;
|
||||||
|
if (serviceUuid.startsWith('0x'))
|
||||||
|
serviceUuid = parseInt(serviceUuid, 16);
|
||||||
|
|
||||||
|
var characteristicUuid = document.getElementById('characteristic').value;
|
||||||
|
if (characteristicUuid.startsWith('0x'))
|
||||||
|
characteristicUuid = parseInt(characteristicUuid, 16);
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
var device = window.navigator.bluetooth.requestDevice({filters: [{services: [serviceUuid]}]});
|
||||||
|
|
||||||
|
log('Connecting to GATTserver on device...');
|
||||||
|
var server = device.gatt.connect();
|
||||||
|
|
||||||
|
log('Getting Primary Service...');
|
||||||
|
var primaryService = server.getPrimaryService(serviceUuid);
|
||||||
|
|
||||||
|
log('Getting Characteristic...');
|
||||||
|
var characteristic = primaryService.getCharacteristic(characteristicUuid);
|
||||||
|
|
||||||
|
log('Characteristic found!');
|
||||||
|
log('> Characteristic service: ' + characteristic.service.uuid);
|
||||||
|
log('> Characteristic UUID: ' + characteristic.uuid);
|
||||||
|
log('> Broadcast: ' + characteristic.properties.broadcast);
|
||||||
|
log('> Read: ' + characteristic.properties.read);
|
||||||
|
log('> Write w/o response: ' + characteristic.properties.writeWithoutResponse);
|
||||||
|
log('> Write: ' + characteristic.properties.write);
|
||||||
|
log('> Notify: ' + characteristic.properties.notify);
|
||||||
|
log('> Indicate: ' + characteristic.properties.indicate);
|
||||||
|
log('> Signed Write: ' + characteristic.properties.authenticatedSignedWrites);
|
||||||
|
log('> Queued Write: ' + characteristic.properties.reliableWrite);
|
||||||
|
log('> Writable Auxiliaries: ' + characteristic.properties.writableAuxiliaries);
|
||||||
|
characteristic.readValue();
|
||||||
|
log('> Characteristic value: ' + AsciiToDecimal(characteristic.value));
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
function AsciiToDecimal(bytestr) {
|
||||||
|
var result = [];
|
||||||
|
for(i = 0; i < bytestr.length; i++) {
|
||||||
|
result[i] = bytestr[i].charCodeAt(0) ;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
68
tests/html/bluetooth_descriptor_info.html
Normal file
68
tests/html/bluetooth_descriptor_info.html
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Descriptor info</title>
|
||||||
|
<body>
|
||||||
|
<input id="service" type="text" autofocus placeholder="Bluetooth Service">
|
||||||
|
<input id="characteristic" type="text" autofocus placeholder="Bluetooth Characteristic">
|
||||||
|
<input id="descriptor" type="text" autofocus placeholder="Bluetooth Descriptor">
|
||||||
|
<button type="button" onclick="onButtonClick()">Get Descriptor Info</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
function onButtonClick() {
|
||||||
|
clear();
|
||||||
|
var serviceUuid = document.getElementById('service').value;
|
||||||
|
if (serviceUuid.startsWith('0x'))
|
||||||
|
serviceUuid = parseInt(serviceUuid, 16);
|
||||||
|
|
||||||
|
var characteristicUuid = document.getElementById('characteristic').value;
|
||||||
|
if (characteristicUuid.startsWith('0x'))
|
||||||
|
characteristicUuid = parseInt(characteristicUuid, 16);
|
||||||
|
|
||||||
|
var descriptorUuid = document.getElementById('descriptor').value;
|
||||||
|
if (descriptorUuid.startsWith('0x'))
|
||||||
|
descriptorUuid = parseInt(descriptorUuid, 16);
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
var device = window.navigator.bluetooth.requestDevice({filters: [{services: [serviceUuid]}]});
|
||||||
|
|
||||||
|
log('Connecting to GATTserver on device...');
|
||||||
|
var server = device.gatt.connect();
|
||||||
|
|
||||||
|
log('Getting Primary Service...');
|
||||||
|
var primaryService = server.getPrimaryService(serviceUuid);
|
||||||
|
|
||||||
|
log('Getting Characteristic...');
|
||||||
|
var characteristic = primaryService.getCharacteristic(characteristicUuid);
|
||||||
|
|
||||||
|
log('Getting Descriptor...');
|
||||||
|
var descriptor = characteristic.getDescriptor(descriptorUuid);
|
||||||
|
|
||||||
|
log('Descriptor found!');
|
||||||
|
log('> Descriptor characteristic: ' + descriptor.characteristic.uuid);
|
||||||
|
log('> Descriptor UUID: ' + descriptor.uuid);
|
||||||
|
descriptor.readValue();
|
||||||
|
log('> Descriptor value: ' + AsciiToDecimal(descriptor.value));
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
function AsciiToDecimal(bytestr) {
|
||||||
|
var result = [];
|
||||||
|
for(i = 0; i < bytestr.length; i++) {
|
||||||
|
result[i] = bytestr[i].charCodeAt(0) ;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
94
tests/html/bluetooth_device_disconnect.html
Normal file
94
tests/html/bluetooth_device_disconnect.html
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Device Disconnect</title>
|
||||||
|
<body>
|
||||||
|
<input id="service" type="text" autofocus placeholder="Bluetooth Service">
|
||||||
|
<input id="name" type="text" placeholder="Device Name">
|
||||||
|
<input id="namePrefix" type="text" placeholder="Device Name Prefix">
|
||||||
|
<button type="button" onclick="onScanButtonClick()">Scan()</button>
|
||||||
|
<button type="button" onclick="onDisconnectButtonClick()">Disconnect()</button>
|
||||||
|
<button type="button" onclick="onReconnectButtonClick()">Reconnect()</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
var bluetoothDevice;
|
||||||
|
|
||||||
|
function onScanButtonClick() {
|
||||||
|
clear();
|
||||||
|
var options = {filters: []};
|
||||||
|
|
||||||
|
var filterService = document.getElementById('service').value;
|
||||||
|
if (filterService.startsWith('0x'))
|
||||||
|
filterService = parseInt(filterService, 16);
|
||||||
|
|
||||||
|
if (filterService)
|
||||||
|
options.filters.push({services: [filterService]});
|
||||||
|
|
||||||
|
var filterName = document.getElementById('name').value;
|
||||||
|
if (filterName)
|
||||||
|
options.filters.push({name: filterName});
|
||||||
|
|
||||||
|
var filterNamePrefix = document.getElementById('namePrefix').value;
|
||||||
|
if (filterNamePrefix)
|
||||||
|
options.filters.push({namePrefix: filterNamePrefix});
|
||||||
|
|
||||||
|
bluetoothDevice = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
bluetoothDevice = window.navigator.bluetooth.requestDevice(options);
|
||||||
|
connect();
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDisconnectButtonClick() {
|
||||||
|
clear();
|
||||||
|
if (!bluetoothDevice)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Disconnecting from Bluetooth Device...');
|
||||||
|
if (bluetoothDevice.gatt.connected) {
|
||||||
|
bluetoothDevice.gatt.disconnect();
|
||||||
|
log('> Bluetooth Device connected: ' + bluetoothDevice.gatt.connected);
|
||||||
|
} else {
|
||||||
|
log('> Bluetooth Device is already disconnected');
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onReconnectButtonClick() {
|
||||||
|
clear();
|
||||||
|
if (!bluetoothDevice)
|
||||||
|
log('> There is no connected Bluetooth Device instance')
|
||||||
|
if (bluetoothDevice.gatt.connected) {
|
||||||
|
log('> Bluetooth Device is already connected');
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function connect() {
|
||||||
|
try {
|
||||||
|
log('Connecting to Bluetooth Device...');
|
||||||
|
bluetoothDevice.gatt.connect();
|
||||||
|
log('> Bluetooth Device connected: ' + bluetoothDevice.gatt.connected);
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
59
tests/html/bluetooth_device_info.html
Normal file
59
tests/html/bluetooth_device_info.html
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Device Info</title>
|
||||||
|
<body>
|
||||||
|
<input id="service" type="text" autofocus placeholder="Bluetooth Service">
|
||||||
|
<input id="name" type="text" placeholder="Device Name">
|
||||||
|
<input id="namePrefix" type="text" placeholder="Device Name Prefix">
|
||||||
|
<button type="button" onclick="onButtonClick()">Get Bluetooth Device Info</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
function onButtonClick() {
|
||||||
|
clear();
|
||||||
|
var options = {filters: [], optinalServices: []};
|
||||||
|
|
||||||
|
var filterService = document.getElementById('service').value;
|
||||||
|
if (filterService.startsWith('0x'))
|
||||||
|
filterService = parseInt(filterService, 16);
|
||||||
|
|
||||||
|
if (filterService)
|
||||||
|
options.filters.push({services: [filterService]});
|
||||||
|
|
||||||
|
var filterName = document.getElementById('name').value;
|
||||||
|
if (filterName)
|
||||||
|
options.filters.push({name: filterName});
|
||||||
|
|
||||||
|
var filterNamePrefix = document.getElementById('namePrefix').value;
|
||||||
|
if (filterNamePrefix)
|
||||||
|
options.filters.push({namePrefix: filterNamePrefix});
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
var device = window.navigator.bluetooth.requestDevice(options);
|
||||||
|
|
||||||
|
log('Found a device!');
|
||||||
|
log('> Name: ' + device.name);
|
||||||
|
log('> Id: ' + device.id);
|
||||||
|
log('> Device Class: ' + device.deviceClass);
|
||||||
|
log('> Vendor Id Source: ' + device.vendorIDSource);
|
||||||
|
log('> Vendor Id: ' + device.vendorID);
|
||||||
|
log('> Product Id: ' + device.productID);
|
||||||
|
log('> Product Version: ' + device.productVersion);
|
||||||
|
log('> Appearance: ' + device.adData.appearance);
|
||||||
|
log('> Tx Power: ' + device.adData.txPower + ' dBm');
|
||||||
|
log('> RSSI: ' + device.adData.rssi + ' dBm');
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
57
tests/html/bluetooth_primary_service_info.html
Normal file
57
tests/html/bluetooth_primary_service_info.html
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<title>Primary Service info</title>
|
||||||
|
<body>
|
||||||
|
<input id="service" type="text" autofocus placeholder="Bluetooth Service">
|
||||||
|
<input id="name" type="text" placeholder="Device Name">
|
||||||
|
<input id="namePrefix" type="text" placeholder="Device Name Prefix">
|
||||||
|
<button type="button" onclick="onButtonClick()">Get Primary Service Info</button>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
<script>
|
||||||
|
function onButtonClick() {
|
||||||
|
clear();
|
||||||
|
var options = {filters: [], optinalServices: []};
|
||||||
|
|
||||||
|
var filterService = document.getElementById('service').value;
|
||||||
|
if (filterService.startsWith('0x'))
|
||||||
|
filterService = parseInt(filterService, 16);
|
||||||
|
|
||||||
|
if (filterService)
|
||||||
|
options.filters.push({services: [filterService]});
|
||||||
|
|
||||||
|
var filterName = document.getElementById('name').value;
|
||||||
|
if (filterName)
|
||||||
|
options.filters.push({name: filterName});
|
||||||
|
|
||||||
|
var filterNamePrefix = document.getElementById('namePrefix').value;
|
||||||
|
if (filterNamePrefix)
|
||||||
|
options.filters.push({namePrefix: filterNamePrefix});
|
||||||
|
|
||||||
|
try {
|
||||||
|
log('Requesting Bluetooth Device...');
|
||||||
|
var device = window.navigator.bluetooth.requestDevice(options);
|
||||||
|
|
||||||
|
log('Connecting to GATTserver on device...');
|
||||||
|
var server = device.gatt.connect();
|
||||||
|
|
||||||
|
log('Getting Primary Service...');
|
||||||
|
var primaryService = server.getPrimaryService(filterService);
|
||||||
|
|
||||||
|
log('Primary Service found on device: ' + primaryService.device.name);
|
||||||
|
log('> UUID: ' + primaryService.uuid);
|
||||||
|
log('> Is primary: ' + primaryService.isPrimary);
|
||||||
|
} catch(err) {
|
||||||
|
log(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
document.getElementById("log").textContent = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function log(line) {
|
||||||
|
document.getElementById("log").textContent += line + '\n';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue