mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +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
|
@ -36,6 +36,7 @@ use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationD
|
|||
use msg::constellation_msg::{SubpageId, WindowSizeData, WindowSizeType};
|
||||
use msg::constellation_msg::{self, ConstellationChan, PanicMsg};
|
||||
use msg::webdriver_msg;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::ImageCacheThread;
|
||||
use net_traits::storage_thread::{StorageThread, StorageThreadMsg};
|
||||
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.
|
||||
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.
|
||||
storage_thread: StorageThread,
|
||||
|
||||
|
@ -197,6 +201,8 @@ pub struct InitialConstellationState {
|
|||
pub compositor_proxy: Box<CompositorProxy + Send>,
|
||||
/// A channel to the developer tools, if applicable.
|
||||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
/// A channel to the bluetooth thread.
|
||||
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
/// A channel to the image cache thread.
|
||||
pub image_cache_thread: ImageCacheThread,
|
||||
/// A channel to the font cache thread.
|
||||
|
@ -338,6 +344,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF>
|
|||
panic_receiver: panic_receiver,
|
||||
compositor_proxy: state.compositor_proxy,
|
||||
devtools_chan: state.devtools_chan,
|
||||
bluetooth_thread: state.bluetooth_thread,
|
||||
resource_thread: state.resource_thread,
|
||||
image_cache_thread: state.image_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(),
|
||||
compositor_proxy: self.compositor_proxy.clone_compositor_proxy(),
|
||||
devtools_chan: self.devtools_chan.clone(),
|
||||
bluetooth_thread: self.bluetooth_thread.clone(),
|
||||
image_cache_thread: self.image_cache_thread.clone(),
|
||||
font_cache_thread: self.font_cache_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) {
|
||||
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.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::{PipelineNamespaceId};
|
||||
use net_traits::ResourceThread;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::ImageCacheThread;
|
||||
use net_traits::storage_thread::StorageThread;
|
||||
use profile_traits::mem as profile_mem;
|
||||
|
@ -92,6 +93,8 @@ pub struct InitialPipelineState {
|
|||
pub compositor_proxy: Box<CompositorProxy + 'static + Send>,
|
||||
/// A channel to the developer tools, if applicable.
|
||||
pub devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
/// A channel to the bluetooth thread.
|
||||
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
/// A channel to the image cache thread.
|
||||
pub image_cache_thread: ImageCacheThread,
|
||||
/// A channel to the font cache thread.
|
||||
|
@ -214,6 +217,7 @@ impl Pipeline {
|
|||
constellation_chan: state.constellation_chan,
|
||||
scheduler_chan: state.scheduler_chan,
|
||||
devtools_chan: script_to_devtools_chan,
|
||||
bluetooth_thread: state.bluetooth_thread,
|
||||
image_cache_thread: state.image_cache_thread,
|
||||
font_cache_thread: state.font_cache_thread.clone(),
|
||||
resource_thread: state.resource_thread,
|
||||
|
@ -390,6 +394,7 @@ pub struct UnprivilegedPipelineContent {
|
|||
scheduler_chan: IpcSender<TimerEventRequest>,
|
||||
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||
script_to_compositor_chan: IpcSender<ScriptToCompositorMsg>,
|
||||
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
image_cache_thread: ImageCacheThread,
|
||||
font_cache_thread: FontCacheThread,
|
||||
resource_thread: ResourceThread,
|
||||
|
@ -430,6 +435,7 @@ impl UnprivilegedPipelineContent {
|
|||
layout_to_constellation_chan: self.layout_to_constellation_chan.clone(),
|
||||
scheduler_chan: self.scheduler_chan.clone(),
|
||||
panic_chan: self.panic_chan.clone(),
|
||||
bluetooth_thread: self.bluetooth_thread.clone(),
|
||||
resource_thread: self.resource_thread,
|
||||
storage_thread: self.storage_thread.clone(),
|
||||
image_cache_thread: self.image_cache_thread.clone(),
|
||||
|
|
|
@ -17,6 +17,8 @@ plugins = {path = "../plugins"}
|
|||
msg = {path = "../msg"}
|
||||
ipc-channel = {git = "https://github.com/servo/ipc-channel"}
|
||||
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" ] }
|
||||
flate2 = "0.2.0"
|
||||
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)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate brotli;
|
||||
extern crate cookie as cookie_rs;
|
||||
extern crate device;
|
||||
extern crate devtools_traits;
|
||||
extern crate flate2;
|
||||
extern crate hyper;
|
||||
|
@ -39,6 +42,7 @@ extern crate webrender_traits;
|
|||
extern crate websocket;
|
||||
|
||||
pub mod about_loader;
|
||||
pub mod bluetooth_thread;
|
||||
pub mod chrome_loader;
|
||||
pub mod cookie;
|
||||
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 websocket::header;
|
||||
|
||||
pub mod bluetooth_scanfilter;
|
||||
pub mod bluetooth_thread;
|
||||
pub mod hosts;
|
||||
pub mod image_cache_thread;
|
||||
pub mod net_error_list;
|
||||
|
|
|
@ -2,12 +2,38 @@
|
|||
* 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 core::clone::Clone;
|
||||
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::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::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
|
||||
#[dom_struct]
|
||||
|
@ -27,13 +53,113 @@ impl Bluetooth {
|
|||
global,
|
||||
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 {
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-requestdevice
|
||||
fn RequestDevice(&self) -> Option<Root<BluetoothDevice>> {
|
||||
//UNIMPLEMENTED
|
||||
None
|
||||
fn RequestDevice(&self, option: &RequestDeviceOptions) -> Fallible<Root<BluetoothDevice>> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
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]
|
||||
pub struct BluetoothAdvertisingData {
|
||||
reflector_: Reflector,
|
||||
appearance: u16,
|
||||
txPower: i8,
|
||||
rssi: i8,
|
||||
appearance: Option<u16>,
|
||||
txPower: Option<i8>,
|
||||
rssi: Option<i8>,
|
||||
}
|
||||
|
||||
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 {
|
||||
reflector_: Reflector::new(),
|
||||
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,
|
||||
txPower,
|
||||
rssi),
|
||||
|
@ -39,16 +46,16 @@ impl BluetoothAdvertisingData {
|
|||
impl BluetoothAdvertisingDataMethods for BluetoothAdvertisingData {
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-appearance
|
||||
fn GetAppearance(&self) -> Option<u16> {
|
||||
Some(self.appearance)
|
||||
self.appearance
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-txpower
|
||||
fn GetTxPower(&self) -> Option<i8> {
|
||||
Some(self.txPower)
|
||||
self.txPower
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothadvertisingdata-rssi
|
||||
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::{BluetoothDeviceMethods, VendorIDSource};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::{JS, Root, MutHeap};
|
||||
use dom::bindings::reflector::{Reflector, reflect_dom_object};
|
||||
use dom::bindings::js::{JS, Root, MutHeap, MutNullableHeap};
|
||||
use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
|
||||
use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
|
||||
use dom::bluetoothremotegattserver::BluetoothRemoteGATTServer;
|
||||
use util::str::DOMString;
|
||||
|
@ -16,26 +16,25 @@ use util::str::DOMString;
|
|||
pub struct BluetoothDevice {
|
||||
reflector_: Reflector,
|
||||
id: DOMString,
|
||||
name: DOMString,
|
||||
name: Option<DOMString>,
|
||||
adData: MutHeap<JS<BluetoothAdvertisingData>>,
|
||||
deviceClass: u32,
|
||||
vendorIDSource: VendorIDSource,
|
||||
vendorID: u32,
|
||||
productID: u32,
|
||||
productVersion: u32,
|
||||
gatt: MutHeap<JS<BluetoothRemoteGATTServer>>,
|
||||
deviceClass: Option<u32>,
|
||||
vendorIDSource: Option<VendorIDSource>,
|
||||
vendorID: Option<u32>,
|
||||
productID: Option<u32>,
|
||||
productVersion: Option<u32>,
|
||||
gatt: MutNullableHeap<JS<BluetoothRemoteGATTServer>>,
|
||||
}
|
||||
|
||||
impl BluetoothDevice {
|
||||
pub fn new_inherited(id: DOMString,
|
||||
name: DOMString,
|
||||
name: Option<DOMString>,
|
||||
adData: &BluetoothAdvertisingData,
|
||||
deviceClass: u32,
|
||||
vendorIDSource: VendorIDSource,
|
||||
vendorID: u32,
|
||||
productID: u32,
|
||||
productVersion: u32,
|
||||
gatt: &BluetoothRemoteGATTServer)
|
||||
deviceClass: Option<u32>,
|
||||
vendorIDSource: Option<VendorIDSource>,
|
||||
vendorID: Option<u32>,
|
||||
productID: Option<u32>,
|
||||
productVersion: Option<u32>)
|
||||
-> BluetoothDevice {
|
||||
BluetoothDevice {
|
||||
reflector_: Reflector::new(),
|
||||
|
@ -47,21 +46,20 @@ impl BluetoothDevice {
|
|||
vendorID: vendorID,
|
||||
productID: productID,
|
||||
productVersion: productVersion,
|
||||
gatt: MutHeap::new(gatt),
|
||||
gatt: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef,
|
||||
id: DOMString,
|
||||
name: DOMString,
|
||||
adData: &BluetoothAdvertisingData,
|
||||
deviceClass: u32,
|
||||
vendorIDSource: VendorIDSource,
|
||||
vendorID: u32,
|
||||
productID: u32,
|
||||
productVersion: u32,
|
||||
gatt: &BluetoothRemoteGATTServer)
|
||||
-> Root<BluetoothDevice> {
|
||||
id: DOMString,
|
||||
name: Option<DOMString>,
|
||||
adData: &BluetoothAdvertisingData,
|
||||
deviceClass: Option<u32>,
|
||||
vendorIDSource: Option<VendorIDSource>,
|
||||
vendorID: Option<u32>,
|
||||
productID: Option<u32>,
|
||||
productVersion: Option<u32>)
|
||||
-> Root<BluetoothDevice> {
|
||||
reflect_dom_object(box BluetoothDevice::new_inherited(id,
|
||||
name,
|
||||
adData,
|
||||
|
@ -69,8 +67,7 @@ impl BluetoothDevice {
|
|||
vendorIDSource,
|
||||
vendorID,
|
||||
productID,
|
||||
productVersion,
|
||||
gatt),
|
||||
productVersion),
|
||||
global,
|
||||
BluetoothDeviceBinding::Wrap)
|
||||
}
|
||||
|
@ -85,7 +82,7 @@ impl BluetoothDeviceMethods for BluetoothDevice {
|
|||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-name
|
||||
fn GetName(&self) -> Option<DOMString> {
|
||||
Some(self.name.clone())
|
||||
self.name.clone()
|
||||
}
|
||||
|
||||
// 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
|
||||
fn GetDeviceClass(&self) -> Option<u32> {
|
||||
Some(self.deviceClass)
|
||||
self.deviceClass
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendoridsource
|
||||
fn GetVendorIDSource(&self) -> Option<VendorIDSource> {
|
||||
Some(self.vendorIDSource)
|
||||
self.vendorIDSource
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-vendorid
|
||||
fn GetVendorID(&self) -> Option<u32> {
|
||||
Some(self.vendorID)
|
||||
self.vendorID
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productid
|
||||
fn GetProductID(&self) -> Option<u32> {
|
||||
Some(self.productID)
|
||||
self.productID
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-productversion
|
||||
fn GetProductVersion(&self) -> Option<u32> {
|
||||
Some(self.productVersion)
|
||||
self.productVersion
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothdevice-gatt
|
||||
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
|
||||
* 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::
|
||||
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::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::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
|
||||
use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
|
||||
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;
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattcharacteristic
|
||||
|
@ -21,33 +30,48 @@ pub struct BluetoothRemoteGATTCharacteristic {
|
|||
service: MutHeap<JS<BluetoothRemoteGATTService>>,
|
||||
uuid: DOMString,
|
||||
properties: MutHeap<JS<BluetoothCharacteristicProperties>>,
|
||||
value: Option<ByteString>,
|
||||
value: DOMRefCell<Option<ByteString>>,
|
||||
instanceID: String,
|
||||
}
|
||||
|
||||
impl BluetoothRemoteGATTCharacteristic {
|
||||
pub fn new_inherited(service: &BluetoothRemoteGATTService,
|
||||
uuid: DOMString,
|
||||
properties: &BluetoothCharacteristicProperties)
|
||||
properties: &BluetoothCharacteristicProperties,
|
||||
instanceID: String)
|
||||
-> BluetoothRemoteGATTCharacteristic {
|
||||
BluetoothRemoteGATTCharacteristic {
|
||||
reflector_: Reflector::new(),
|
||||
service: MutHeap::new(service),
|
||||
uuid: uuid,
|
||||
properties: MutHeap::new(properties),
|
||||
value: None,
|
||||
value: DOMRefCell::new(None),
|
||||
instanceID: instanceID,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef,
|
||||
service: &BluetoothRemoteGATTService,
|
||||
uuid: DOMString,
|
||||
properties: &BluetoothCharacteristicProperties)
|
||||
properties: &BluetoothCharacteristicProperties,
|
||||
instanceID: String)
|
||||
-> Root<BluetoothRemoteGATTCharacteristic> {
|
||||
reflect_dom_object(box BluetoothRemoteGATTCharacteristic::new_inherited(service,
|
||||
uuid,
|
||||
properties),
|
||||
global,
|
||||
BluetoothRemoteGATTCharacteristicBinding::Wrap)
|
||||
properties,
|
||||
instanceID),
|
||||
global,
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -69,19 +93,89 @@ impl BluetoothRemoteGATTCharacteristicMethods for BluetoothRemoteGATTCharacteris
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
|
||||
fn GetDescriptor(&self) -> Option<Root<BluetoothRemoteGATTDescriptor>> {
|
||||
//UNIMPLEMENTED
|
||||
None
|
||||
fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> {
|
||||
let uuid = try!(BluetoothUUID::GetDescriptor(self.global().r(), descriptor)).to_string();
|
||||
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
|
||||
fn GetValue(&self) -> Option<ByteString> {
|
||||
self.value.clone()
|
||||
self.value.borrow().clone()
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
|
||||
fn ReadValue(&self) -> ByteString {
|
||||
//UNIMPLEMENTED
|
||||
ByteString::new(vec!())
|
||||
fn ReadValue(&self) -> Fallible<ByteString> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
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
|
||||
* 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::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::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::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use util::str::DOMString;
|
||||
|
||||
// http://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattdescriptor
|
||||
|
@ -17,30 +27,45 @@ pub struct BluetoothRemoteGATTDescriptor {
|
|||
reflector_: Reflector,
|
||||
characteristic: MutHeap<JS<BluetoothRemoteGATTCharacteristic>>,
|
||||
uuid: DOMString,
|
||||
value: Option<ByteString>,
|
||||
value: DOMRefCell<Option<ByteString>>,
|
||||
instanceID: String,
|
||||
}
|
||||
|
||||
impl BluetoothRemoteGATTDescriptor {
|
||||
pub fn new_inherited(characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
uuid: DOMString)
|
||||
uuid: DOMString,
|
||||
instanceID: String)
|
||||
-> BluetoothRemoteGATTDescriptor {
|
||||
BluetoothRemoteGATTDescriptor {
|
||||
reflector_: Reflector::new(),
|
||||
characteristic: MutHeap::new(characteristic),
|
||||
uuid: uuid,
|
||||
value: None,
|
||||
value: DOMRefCell::new(None),
|
||||
instanceID: instanceID,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef,
|
||||
characteristic: &BluetoothRemoteGATTCharacteristic,
|
||||
uuid: DOMString)
|
||||
uuid: DOMString,
|
||||
instanceID: String)
|
||||
-> Root<BluetoothRemoteGATTDescriptor>{
|
||||
reflect_dom_object(box BluetoothRemoteGATTDescriptor::new_inherited(characteristic,
|
||||
uuid),
|
||||
uuid,
|
||||
instanceID),
|
||||
global,
|
||||
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 {
|
||||
|
@ -57,12 +82,41 @@ impl BluetoothRemoteGATTDescriptorMethods for BluetoothRemoteGATTDescriptor {
|
|||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value
|
||||
fn GetValue(&self) -> Option<ByteString> {
|
||||
self.value.clone()
|
||||
self.value.borrow().clone()
|
||||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
|
||||
fn ReadValue(&self) -> ByteString {
|
||||
//UNIMPLEMENTED
|
||||
ByteString::new(vec!())
|
||||
fn ReadValue(&self) -> Fallible<ByteString> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
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
|
||||
* 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::BluetoothRemoteGATTServerMethods;
|
||||
use dom::bindings::error::Error::Type;
|
||||
use dom::bindings::error::{Fallible, ErrorResult};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
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::bluetoothremotegattservice::BluetoothRemoteGATTService;
|
||||
use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use std::cell::Cell;
|
||||
use util::str::DOMString;
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattserver
|
||||
#[dom_struct]
|
||||
|
@ -20,21 +27,25 @@ pub struct BluetoothRemoteGATTServer {
|
|||
}
|
||||
|
||||
impl BluetoothRemoteGATTServer {
|
||||
pub fn new_inherited(device: &BluetoothDevice, is_connected: bool) -> BluetoothRemoteGATTServer {
|
||||
pub fn new_inherited(device: &BluetoothDevice) -> BluetoothRemoteGATTServer {
|
||||
BluetoothRemoteGATTServer {
|
||||
reflector_: Reflector::new(),
|
||||
device: MutHeap::new(device),
|
||||
connected: Cell::new(is_connected),
|
||||
connected: Cell::new(false),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef, device: &BluetoothDevice, connected: bool) -> Root<BluetoothRemoteGATTServer> {
|
||||
reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited(
|
||||
device,
|
||||
connected),
|
||||
pub fn new(global: GlobalRef, device: &BluetoothDevice) -> Root<BluetoothRemoteGATTServer> {
|
||||
reflect_dom_object(box BluetoothRemoteGATTServer::new_inherited(device),
|
||||
global,
|
||||
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 {
|
||||
|
@ -50,21 +61,85 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
|
||||
fn Connect(&self) -> Root<BluetoothRemoteGATTServer> {
|
||||
if !self.connected.get() {
|
||||
self.connected.set(true);
|
||||
fn Connect(&self) -> Fallible<Root<BluetoothRemoteGATTServer>> {
|
||||
let (sender, receiver) = ipc::channel().unwrap();
|
||||
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
|
||||
fn Disconnect(&self) {
|
||||
self.connected.set(false);
|
||||
fn Disconnect(&self) -> ErrorResult {
|
||||
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
|
||||
fn GetPrimaryService(&self) -> Option<Root<BluetoothRemoteGATTService>> {
|
||||
//UNIMPLEMENTED
|
||||
None
|
||||
fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> {
|
||||
let uuid = try!(BluetoothUUID::GetService(self.global().r(), service)).to_string();
|
||||
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::BluetoothRemoteGATTServiceMethods;
|
||||
use dom::bindings::error::Error::Type;
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
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::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
|
||||
use dom::bluetoothuuid::{BluetoothCharacteristicUUID, BluetoothUUID};
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use util::str::DOMString;
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothremotegattservice
|
||||
|
@ -18,32 +24,47 @@ pub struct BluetoothRemoteGATTService {
|
|||
device: MutHeap<JS<BluetoothDevice>>,
|
||||
uuid: DOMString,
|
||||
isPrimary: bool,
|
||||
instanceID: String,
|
||||
}
|
||||
|
||||
impl BluetoothRemoteGATTService {
|
||||
pub fn new_inherited(device: &BluetoothDevice,
|
||||
uuid: DOMString,
|
||||
isPrimary: bool)
|
||||
isPrimary: bool,
|
||||
instanceID: String)
|
||||
-> BluetoothRemoteGATTService {
|
||||
BluetoothRemoteGATTService {
|
||||
reflector_: Reflector::new(),
|
||||
device: MutHeap::new(device),
|
||||
uuid: uuid,
|
||||
isPrimary: isPrimary,
|
||||
instanceID: instanceID,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(global: GlobalRef,
|
||||
device: &BluetoothDevice,
|
||||
uuid: DOMString,
|
||||
isPrimary: bool)
|
||||
isPrimary: bool,
|
||||
instanceID: String)
|
||||
-> Root<BluetoothRemoteGATTService> {
|
||||
reflect_dom_object(box BluetoothRemoteGATTService::new_inherited(device,
|
||||
uuid,
|
||||
isPrimary),
|
||||
isPrimary,
|
||||
instanceID),
|
||||
global,
|
||||
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 {
|
||||
|
@ -63,8 +84,75 @@ impl BluetoothRemoteGATTServiceMethods for BluetoothRemoteGATTService {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
|
||||
fn GetCharacteristic(&self) -> Option<Root<BluetoothRemoteGATTCharacteristic>> {
|
||||
// UNIMPLEMENTED
|
||||
None
|
||||
fn GetCharacteristic(&self,
|
||||
characteristic: BluetoothCharacteristicUUID)
|
||||
-> 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;
|
||||
|
||||
pub type UUID = DOMString;
|
||||
pub type BluetoothServiceUUID = StringOrUnsignedLong;
|
||||
pub type BluetoothCharacteristicUUID = StringOrUnsignedLong;
|
||||
pub type BluetoothDescriptorUUID = StringOrUnsignedLong;
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#bluetoothuuid
|
||||
#[dom_struct]
|
||||
|
@ -18,27 +21,246 @@ pub struct BluetoothUUID {
|
|||
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
|
||||
const BLUETOOTH_ASSIGNED_SERVICES: &'static [(&'static str, u32)] = &[
|
||||
("org.bluetooth.service.alert_notification", 0x1811_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
|
||||
const BLUETOOTH_ASSIGNED_CHARCTERISTICS: &'static [(&'static str, u32)] = &[
|
||||
("org.bluetooth.characteristic.aerobic_heart_rate_lower_limit", 0x2a7e_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
|
||||
const BLUETOOTH_ASSIGNED_DESCRIPTORS: &'static [(&'static str, 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";
|
||||
|
@ -55,9 +277,7 @@ impl BluetoothUUID {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getservice
|
||||
pub fn GetService(globalref: GlobalRef,
|
||||
name: StringOrUnsignedLong)
|
||||
-> Fallible<UUID> {
|
||||
pub fn GetService(globalref: GlobalRef, name: BluetoothServiceUUID) -> Fallible<UUID> {
|
||||
BluetoothUUID::resolve_uuid_name(globalref,
|
||||
name,
|
||||
BLUETOOTH_ASSIGNED_SERVICES,
|
||||
|
@ -65,9 +285,7 @@ impl BluetoothUUID {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getcharacteristic
|
||||
pub fn GetCharacteristic(globalref: GlobalRef,
|
||||
name: StringOrUnsignedLong)
|
||||
-> Fallible<UUID> {
|
||||
pub fn GetCharacteristic(globalref: GlobalRef, name: BluetoothCharacteristicUUID) -> Fallible<UUID> {
|
||||
BluetoothUUID::resolve_uuid_name(globalref,
|
||||
name,
|
||||
BLUETOOTH_ASSIGNED_CHARCTERISTICS,
|
||||
|
@ -75,9 +293,7 @@ impl BluetoothUUID {
|
|||
}
|
||||
|
||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothuuid-getdescriptor
|
||||
pub fn GetDescriptor(globalref: GlobalRef,
|
||||
name: StringOrUnsignedLong)
|
||||
-> Fallible<UUID> {
|
||||
pub fn GetDescriptor(globalref: GlobalRef, name: BluetoothDescriptorUUID) -> Fallible<UUID> {
|
||||
BluetoothUUID::resolve_uuid_name(globalref,
|
||||
name,
|
||||
BLUETOOTH_ASSIGNED_DESCRIPTORS,
|
||||
|
@ -92,7 +308,7 @@ impl BluetoothUUID {
|
|||
-> Fallible<DOMString> {
|
||||
match name {
|
||||
// Step 1
|
||||
StringOrUnsignedLong::UnsignedLong(unsigned32) =>{
|
||||
StringOrUnsignedLong::UnsignedLong(unsigned32) => {
|
||||
Ok(BluetoothUUID::CanonicalUUID(globalref, unsigned32))
|
||||
},
|
||||
StringOrUnsignedLong::String(dstring) => {
|
||||
|
@ -103,8 +319,7 @@ impl BluetoothUUID {
|
|||
} else {
|
||||
// Step 3
|
||||
let concatenated = format!("{}.{}", prefix, dstring);
|
||||
let is_in_table = assigned_numbers_table.iter()
|
||||
.find(|p| p.0 == concatenated);
|
||||
let is_in_table = assigned_numbers_table.iter().find(|p| p.0 == concatenated);
|
||||
match is_in_table {
|
||||
Some(&(_, alias)) => Ok(BluetoothUUID::CanonicalUUID(globalref, alias)),
|
||||
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
|
||||
|
||||
dictionary BluetoothScanFilter {
|
||||
sequence<BluetoothServiceUUID> services;
|
||||
DOMString name;
|
||||
DOMString namePrefix;
|
||||
};
|
||||
|
||||
dictionary RequestDeviceOptions {
|
||||
required sequence<BluetoothScanFilter> filters;
|
||||
sequence<BluetoothServiceUUID> optionalServices /*= []*/;
|
||||
};
|
||||
|
||||
[Pref="dom.bluetooth.enabled"]
|
||||
interface Bluetooth {
|
||||
// Promise<BluetoothDevice> requestDevice(RequestDeviceOptions options);
|
||||
BluetoothDevice? requestDevice(/*RequestDeviceOptions options*/);
|
||||
[Throws]
|
||||
BluetoothDevice requestDevice(RequestDeviceOptions options);
|
||||
};
|
||||
|
||||
// Bluetooth implements EventTarget;
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
// Allocation authorities for Vendor IDs:
|
||||
enum VendorIDSource {
|
||||
"bluetooth",
|
||||
"usb"
|
||||
"usb",
|
||||
"unknown"
|
||||
};
|
||||
|
||||
[Pref="dom.bluetooth.enabled"]
|
||||
|
|
|
@ -10,12 +10,18 @@ interface BluetoothRemoteGATTCharacteristic {
|
|||
readonly attribute DOMString uuid;
|
||||
readonly attribute BluetoothCharacteristicProperties properties;
|
||||
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<sequence<BluetoothRemoteGATTDescriptor>>
|
||||
//getDescriptors(optional BluetoothDescriptorUUID descriptor);
|
||||
//Promise<DataView> readValue();
|
||||
[Throws]
|
||||
ByteString readValue();
|
||||
//Promise<DataView> readValue();
|
||||
[Throws]
|
||||
void writeValue(sequence<octet> value);
|
||||
//Promise<void> writeValue(BufferSource value);
|
||||
//Promise<void> startNotifications();
|
||||
//Promise<void> stopNotifications();
|
||||
|
|
|
@ -9,8 +9,10 @@ interface BluetoothRemoteGATTDescriptor {
|
|||
readonly attribute BluetoothRemoteGATTCharacteristic characteristic;
|
||||
readonly attribute DOMString uuid;
|
||||
readonly attribute ByteString? value;
|
||||
|
||||
[Throws]
|
||||
ByteString readValue();
|
||||
//Promise<DataView> readValue();
|
||||
[Throws]
|
||||
void writeValue(sequence<octet> value);
|
||||
//Promise<void> writeValue(BufferSource value);
|
||||
};
|
||||
|
|
|
@ -8,9 +8,14 @@
|
|||
interface BluetoothRemoteGATTServer {
|
||||
readonly attribute BluetoothDevice device;
|
||||
readonly attribute boolean connected;
|
||||
[Throws]
|
||||
BluetoothRemoteGATTServer connect();
|
||||
[Throws]
|
||||
void disconnect();
|
||||
BluetoothRemoteGATTService? getPrimaryService();
|
||||
[Throws]
|
||||
BluetoothRemoteGATTService getPrimaryService(BluetoothServiceUUID service);
|
||||
[Throws]
|
||||
sequence<BluetoothRemoteGATTService> getPrimaryServices(optional BluetoothServiceUUID service);
|
||||
//Promise<BluetoothRemoteGATTService> getPrimaryService(BluetoothServiceUUID service);
|
||||
//Promise<sequence<BluetoothRemoteGATTService>>getPrimaryServices(optional BluetoothServiceUUID service);
|
||||
//Promise<BluetoothRemoteGATTServer> connect();
|
||||
|
|
|
@ -9,7 +9,11 @@ interface BluetoothRemoteGATTService {
|
|||
readonly attribute BluetoothDevice device;
|
||||
readonly attribute DOMString uuid;
|
||||
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<sequence<BluetoothRemoteGATTCharacteristic>>
|
||||
//getCharacteristics(optional BluetoothCharacteristicUUID characteristic);
|
||||
|
|
|
@ -47,6 +47,7 @@ use msg::constellation_msg::{ConstellationChan, LoadData, PipelineId, SubpageId}
|
|||
use msg::constellation_msg::{WindowSizeData, WindowSizeType};
|
||||
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||
use net_traits::ResourceThread;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheThread};
|
||||
use net_traits::storage_thread::{StorageThread, StorageType};
|
||||
use num_traits::ToPrimitive;
|
||||
|
@ -212,6 +213,10 @@ pub struct Window {
|
|||
#[ignore_heap_size_of = "channels are hard"]
|
||||
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.
|
||||
#[ignore_heap_size_of = "channels are hard"]
|
||||
storage_thread: StorageThread,
|
||||
|
@ -334,6 +339,10 @@ impl Window {
|
|||
&*self.page
|
||||
}
|
||||
|
||||
pub fn bluetooth_thread(&self) -> IpcSender<BluetoothMethodMsg> {
|
||||
self.bluetooth_thread.clone()
|
||||
}
|
||||
|
||||
pub fn storage_thread(&self) -> StorageThread {
|
||||
self.storage_thread.clone()
|
||||
}
|
||||
|
@ -1407,6 +1416,7 @@ impl Window {
|
|||
compositor: IpcSender<ScriptToCompositorMsg>,
|
||||
image_cache_thread: ImageCacheThread,
|
||||
resource_thread: Arc<ResourceThread>,
|
||||
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
storage_thread: StorageThread,
|
||||
mem_profiler_chan: mem::ProfilerChan,
|
||||
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||
|
@ -1462,6 +1472,7 @@ impl Window {
|
|||
dom_static: GlobalStaticData::new(),
|
||||
js_runtime: DOMRefCell::new(Some(runtime.clone())),
|
||||
resource_thread: resource_thread,
|
||||
bluetooth_thread: bluetooth_thread,
|
||||
storage_thread: storage_thread,
|
||||
constellation_chan: constellation_chan,
|
||||
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::webdriver_msg::WebDriverScriptCommand;
|
||||
use net_traits::LoadData as NetLoadData;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
|
||||
use net_traits::storage_thread::StorageThread;
|
||||
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
|
||||
/// there are many iframes.
|
||||
resource_thread: Arc<ResourceThread>,
|
||||
/// A handle to the bluetooth thread.
|
||||
bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
/// A handle to the storage thread.
|
||||
storage_thread: StorageThread,
|
||||
|
||||
|
@ -554,6 +557,7 @@ impl ScriptThread {
|
|||
image_cache_port: image_cache_port,
|
||||
|
||||
resource_thread: Arc::new(state.resource_thread),
|
||||
bluetooth_thread: state.bluetooth_thread,
|
||||
storage_thread: state.storage_thread,
|
||||
|
||||
port: port,
|
||||
|
@ -1496,6 +1500,7 @@ impl ScriptThread {
|
|||
self.compositor.borrow_mut().clone(),
|
||||
self.image_cache_thread.clone(),
|
||||
self.resource_thread.clone(),
|
||||
self.bluetooth_thread.clone(),
|
||||
self.storage_thread.clone(),
|
||||
self.mem_profiler_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::webdriver_msg::WebDriverScriptCommand;
|
||||
use net_traits::ResourceThread;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::image_cache_thread::ImageCacheThread;
|
||||
use net_traits::response::HttpsState;
|
||||
use net_traits::storage_thread::StorageThread;
|
||||
|
@ -320,6 +321,8 @@ pub struct InitialScriptState {
|
|||
pub scheduler_chan: IpcSender<TimerEventRequest>,
|
||||
/// A channel to the resource manager thread.
|
||||
pub resource_thread: ResourceThread,
|
||||
/// A channel to the bluetooth thread.
|
||||
pub bluetooth_thread: IpcSender<BluetoothMethodMsg>,
|
||||
/// A channel to the storage thread.
|
||||
pub storage_thread: StorageThread,
|
||||
/// 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"
|
||||
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]]
|
||||
name = "brotli"
|
||||
version = "0.3.20"
|
||||
|
@ -414,6 +423,15 @@ dependencies = [
|
|||
"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]]
|
||||
name = "debug_unreachable"
|
||||
version = "0.1.1"
|
||||
|
@ -430,6 +448,14 @@ dependencies = [
|
|||
"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]]
|
||||
name = "devtools"
|
||||
version = "0.0.1"
|
||||
|
@ -1305,8 +1331,10 @@ dependencies = [
|
|||
name = "net"
|
||||
version = "0.0.1"
|
||||
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)",
|
||||
"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",
|
||||
"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)",
|
||||
|
|
|
@ -71,9 +71,11 @@ use compositing::{CompositorProxy, CompositorThread, Constellation};
|
|||
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
|
||||
use gfx::font_cache_thread::FontCacheThread;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use net::bluetooth_thread::BluetoothThreadFactory;
|
||||
use net::image_cache_thread::new_image_cache_thread;
|
||||
use net::resource_thread::new_resource_thread;
|
||||
use net::storage_thread::StorageThreadFactory;
|
||||
use net_traits::bluetooth_thread::BluetoothMethodMsg;
|
||||
use net_traits::storage_thread::StorageThread;
|
||||
use profile::mem as profile_mem;
|
||||
use profile::time as profile_time;
|
||||
|
@ -208,6 +210,7 @@ fn create_constellation(opts: opts::Opts,
|
|||
devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
|
||||
supports_clipboard: bool,
|
||||
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 image_cache_thread = new_image_cache_thread(resource_thread.clone(),
|
||||
webrender_api_sender.as_ref().map(|wr| wr.create_api()));
|
||||
|
@ -218,6 +221,7 @@ fn create_constellation(opts: opts::Opts,
|
|||
let initial_state = InitialConstellationState {
|
||||
compositor_proxy: compositor_proxy,
|
||||
devtools_chan: devtools_chan,
|
||||
bluetooth_thread: bluetooth_thread,
|
||||
image_cache_thread: image_cache_thread,
|
||||
font_cache_thread: font_cache_thread,
|
||||
resource_thread: resource_thread,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue