Skip to content

Commit

Permalink
WebBluetooth Test API
Browse files Browse the repository at this point in the history
  • Loading branch information
zakorgy committed Nov 4, 2016
1 parent 4eec2c6 commit e15d54e
Show file tree
Hide file tree
Showing 14 changed files with 701 additions and 14 deletions.
3 changes: 2 additions & 1 deletion components/bluetooth/Cargo.toml
Expand Up @@ -12,10 +12,11 @@ path = "lib.rs"
[dependencies]
bitflags = "0.7"
bluetooth_traits = {path = "../bluetooth_traits"}
device = {git = "https://github.com/servo/devices"}
device = {git = "https://github.com/servo/devices", features = ["bluetooth-test"]}
ipc-channel = "0.5"
rand = "0.3"
util = {path = "../util"}
uuid = {version = "0.3.1", features = ["v4"]}

[target.'cfg(target_os = "linux")'.dependencies]
tinyfiledialogs = {git = "https://github.com/jdm/tinyfiledialogs"}
90 changes: 78 additions & 12 deletions components/bluetooth/lib.rs
Expand Up @@ -11,17 +11,17 @@ extern crate rand;
#[cfg(target_os = "linux")]
extern crate tinyfiledialogs;
extern crate util;
extern crate uuid;

pub mod test;

use bluetooth_traits::{BluetoothCharacteristicMsg, BluetoothCharacteristicsMsg};
use bluetooth_traits::{BluetoothDescriptorMsg, BluetoothDescriptorsMsg};
use bluetooth_traits::{BluetoothDeviceMsg, BluetoothError, BluetoothMethodMsg};
use bluetooth_traits::{BluetoothResult, BluetoothServiceMsg, BluetoothServicesMsg};
use bluetooth_traits::scanfilter::{BluetoothScanfilter, BluetoothScanfilterSequence, RequestDeviceoptions};
use device::bluetooth::BluetoothAdapter;
use device::bluetooth::BluetoothDevice;
use device::bluetooth::BluetoothGATTCharacteristic;
use device::bluetooth::BluetoothGATTDescriptor;
use device::bluetooth::BluetoothGATTService;
use device::bluetooth::{BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic};
use device::bluetooth::{BluetoothGATTDescriptor, BluetoothGATTService};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use rand::Rng;
use std::borrow::ToOwned;
Expand All @@ -33,6 +33,8 @@ use util::thread::spawn_named;

const ADAPTER_ERROR: &'static str = "No adapter found";

const ADAPTER_NOT_POWERED_ERROR: &'static str = "Bluetooth adapter not powered";

// A transaction not completed within 30 seconds shall time out. Such a transaction shall be considered to have failed.
// https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=286439 (Vol. 3, page 480)
const MAXIMUM_TRANSACTION_TIME: u8 = 30;
Expand Down Expand Up @@ -71,7 +73,12 @@ macro_rules! return_if_cached(
macro_rules! get_adapter_or_return_error(
($bl_manager:expr, $sender:expr) => (
match $bl_manager.get_or_create_adapter() {
Some(adapter) => adapter,
Some(adapter) => {
if !adapter.is_powered().unwrap_or(false) {
return drop($sender.send(Err(BluetoothError::Type(ADAPTER_NOT_POWERED_ERROR.to_string()))))
}
adapter
},
None => return drop($sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))),
}
);
Expand Down Expand Up @@ -155,6 +162,13 @@ fn matches_filters(device: &BluetoothDevice, filters: &BluetoothScanfilterSequen
return filters.iter().any(|f| matches_filter(device, f))
}

fn is_mock_adapter(adapter: &BluetoothAdapter) -> bool {
match adapter {
&BluetoothAdapter::Mock(_) => true,
_ => false,
}
}

pub struct BluetoothManager {
receiver: IpcReceiver<BluetoothMethodMsg>,
adapter: Option<BluetoothAdapter>,
Expand Down Expand Up @@ -228,20 +242,56 @@ impl BluetoothManager {
BluetoothMethodMsg::WriteValue(id, value, sender) => {
self.write_value(id, value, sender)
},
BluetoothMethodMsg::Test(data_set_name, sender) => {
self.test(data_set_name, sender)
}
BluetoothMethodMsg::Exit => {
break
},
}
}
}

// Test

fn test(&mut self, data_set_name: String, sender: IpcSender<BluetoothResult<()>>) {
self.address_to_id.clear();
self.service_to_device.clear();
self.characteristic_to_service.clear();
self.descriptor_to_characteristic.clear();
self.cached_devices.clear();
self.cached_services.clear();
self.cached_characteristics.clear();
self.cached_descriptors.clear();
self.allowed_services.clear();
self.adapter = BluetoothAdapter::init_mock().ok();
match test::test(self, data_set_name) {
Ok(_) => {
let _ = sender.send(Ok(()));
},
Err(error) => {
let _ = sender.send(Err(BluetoothError::Type(error.description().to_owned())));
},
}
}

// Adapter

fn get_or_create_adapter(&mut self) -> Option<BluetoothAdapter> {
pub 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();
}

let adapter = match self.adapter.as_ref() {
Some(adapter) => adapter,
None => return None,
};

if is_mock_adapter(adapter) && !adapter.is_present().unwrap_or(false) {
return None;
}

self.adapter.clone()
}

Expand Down Expand Up @@ -270,7 +320,16 @@ impl BluetoothManager {
}

#[cfg(target_os = "linux")]
fn select_device(&mut self, devices: Vec<BluetoothDevice>) -> Option<String> {
fn select_device(&mut self, devices: Vec<BluetoothDevice>, adapter: &BluetoothAdapter) -> Option<String> {
if is_mock_adapter(adapter) {
for device in devices {
if let Ok(address) = device.get_address() {
return Some(address);
}
}
return None;
}

let mut dialog_rows: Vec<String> = vec!();
for device in devices {
dialog_rows.extend_from_slice(&[device.get_address().unwrap_or("".to_string()),
Expand All @@ -291,7 +350,7 @@ impl BluetoothManager {
}

#[cfg(not(target_os = "linux"))]
fn select_device(&mut self, devices: Vec<BluetoothDevice>) -> Option<String> {
fn select_device(&mut self, devices: Vec<BluetoothDevice>, _adapter: &BluetoothAdapter) -> Option<String> {
for device in devices {
if let Ok(address) = device.get_address() {
return Some(address);
Expand Down Expand Up @@ -475,7 +534,9 @@ impl BluetoothManager {
let mut adapter = get_adapter_or_return_error!(self, sender);
if let Ok(ref session) = adapter.create_discovery_session() {
if session.start_discovery().is_ok() {
thread::sleep(Duration::from_millis(DISCOVERY_TIMEOUT_MS));
if !is_mock_adapter(&adapter) {
thread::sleep(Duration::from_millis(DISCOVERY_TIMEOUT_MS));
}
}
let _ = session.stop_discovery();
}
Expand All @@ -492,7 +553,7 @@ impl BluetoothManager {
}

// Step 8.
if let Some(address) = self.select_device(matched_devices) {
if let Some(address) = self.select_device(matched_devices, &adapter) {
let device_id = match self.address_to_id.get(&address) {
Some(id) => id.clone(),
None => return drop(sender.send(Err(BluetoothError::NotFound))),
Expand Down Expand Up @@ -528,7 +589,12 @@ impl BluetoothManager {
for _ in 0..MAXIMUM_TRANSACTION_TIME {
match d.is_connected().unwrap_or(false) {
true => return drop(sender.send(Ok(true))),
false => thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS)),
false => {
if is_mock_adapter(&adapter) {
break;
}
thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS));
},
}
}
return drop(sender.send(Err(BluetoothError::Network)));
Expand Down

0 comments on commit e15d54e

Please sign in to comment.