diff options
Diffstat (limited to 'components/bluetooth/lib.rs')
-rw-r--r-- | components/bluetooth/lib.rs | 113 |
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() { |