aboutsummaryrefslogtreecommitdiffstats
path: root/components/bluetooth/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/bluetooth/lib.rs')
-rw-r--r--components/bluetooth/lib.rs113
1 files changed, 99 insertions, 14 deletions
diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs
index 12ba83244be..e3d4eba1a24 100644
--- a/components/bluetooth/lib.rs
+++ b/components/bluetooth/lib.rs
@@ -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;
@@ -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;
@@ -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())))),
}
);
@@ -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>,
@@ -228,6 +242,9 @@ 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
},
@@ -235,13 +252,46 @@ impl BluetoothManager {
}
}
+ // 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()
}
@@ -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()),
@@ -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);
@@ -312,6 +371,17 @@ impl BluetoothManager {
device_id
}
+ fn device_from_service_id(&self, service_id: &str) -> Option<BluetoothDevice> {
+ let device_id = match self.service_to_device.get(service_id) {
+ Some(id) => id,
+ None => return None,
+ };
+ match self.cached_devices.get(device_id) {
+ Some(d) => Some(d.clone()),
+ None => None,
+ }
+ }
+
// Service
fn get_and_cache_gatt_services(&mut self,
@@ -464,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();
}
@@ -481,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))),
@@ -517,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)));
@@ -617,11 +694,15 @@ impl BluetoothManager {
Some(a) => a,
None => return drop(sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))),
};
+ let device = match self.device_from_service_id(&service_id) {
+ Some(device) => device,
+ None => return drop(sender.send(Err(BluetoothError::NotFound))),
+ };
let primary_service = match self.get_gatt_service(&mut adapter, &service_id) {
Some(s) => s,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
};
- let services = primary_service.get_includes().unwrap_or(vec!());
+ let services = primary_service.get_includes(device).unwrap_or(vec!());
for service in services {
if let Ok(service_uuid) = service.get_uuid() {
if uuid == service_uuid {
@@ -644,11 +725,15 @@ impl BluetoothManager {
Some(a) => a,
None => return drop(sender.send(Err(BluetoothError::Type(ADAPTER_ERROR.to_string())))),
};
+ let device = match self.device_from_service_id(&service_id) {
+ Some(device) => device,
+ None => return drop(sender.send(Err(BluetoothError::NotFound))),
+ };
let primary_service = match self.get_gatt_service(&mut adapter, &service_id) {
Some(s) => s,
None => return drop(sender.send(Err(BluetoothError::NotFound))),
};
- let services = primary_service.get_includes().unwrap_or(vec!());
+ let services = primary_service.get_includes(device).unwrap_or(vec!());
let mut services_vec = vec!();
for service in services {
if let Ok(service_uuid) = service.get_uuid() {