mirror of
https://github.com/servo/servo.git
synced 2025-07-31 19:20:22 +01:00
Auto merge of #21442 - kingdido999:rustfmt/bluetooth, r=jdm
Format components bluetooth and bluetooth_traits <!-- Please describe your changes on the following line: --> ```bash rustfmt components/bluetooth/*.rs rustfmt components/bluetooth_traits/*.rs ``` --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes fix a part of #21373 . - [x] These changes do not require tests because it's code format change. <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/21442) <!-- Reviewable:end -->
This commit is contained in:
commit
ad83faa745
5 changed files with 486 additions and 340 deletions
|
@ -75,9 +75,12 @@ impl BluetoothThreadFactory for IpcSender<BluetoothRequest> {
|
||||||
} else {
|
} else {
|
||||||
BluetoothAdapter::init_mock()
|
BluetoothAdapter::init_mock()
|
||||||
}.ok();
|
}.ok();
|
||||||
thread::Builder::new().name("BluetoothThread".to_owned()).spawn(move || {
|
thread::Builder::new()
|
||||||
BluetoothManager::new(receiver, adapter, embedder_proxy).start();
|
.name("BluetoothThread".to_owned())
|
||||||
}).expect("Thread spawning failed");
|
.spawn(move || {
|
||||||
|
BluetoothManager::new(receiver, adapter, embedder_proxy).start();
|
||||||
|
})
|
||||||
|
.expect("Thread spawning failed");
|
||||||
sender
|
sender
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +182,7 @@ fn matches_filters(device: &BluetoothDevice, filters: &BluetoothScanfilterSequen
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return filters.iter().any(|f| matches_filter(device, f))
|
return filters.iter().any(|f| matches_filter(device, f));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_mock_adapter(adapter: &BluetoothAdapter) -> bool {
|
fn is_mock_adapter(adapter: &BluetoothAdapter) -> bool {
|
||||||
|
@ -205,9 +208,11 @@ pub struct BluetoothManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothManager {
|
impl BluetoothManager {
|
||||||
pub fn new(receiver: IpcReceiver<BluetoothRequest>,
|
pub fn new(
|
||||||
adapter: Option<BluetoothAdapter>,
|
receiver: IpcReceiver<BluetoothRequest>,
|
||||||
embedder_proxy: EmbedderProxy) -> BluetoothManager {
|
adapter: Option<BluetoothAdapter>,
|
||||||
|
embedder_proxy: EmbedderProxy,
|
||||||
|
) -> BluetoothManager {
|
||||||
BluetoothManager {
|
BluetoothManager {
|
||||||
receiver: receiver,
|
receiver: receiver,
|
||||||
adapter: adapter,
|
adapter: adapter,
|
||||||
|
@ -254,9 +259,11 @@ impl BluetoothManager {
|
||||||
BluetoothRequest::Test(data_set_name, sender) => {
|
BluetoothRequest::Test(data_set_name, sender) => {
|
||||||
let _ = sender.send(self.test(data_set_name));
|
let _ = sender.send(self.test(data_set_name));
|
||||||
},
|
},
|
||||||
BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids) => {
|
BluetoothRequest::SetRepresentedToNull(
|
||||||
self.remove_ids_from_caches(service_ids, characteristic_ids, descriptor_ids)
|
service_ids,
|
||||||
},
|
characteristic_ids,
|
||||||
|
descriptor_ids,
|
||||||
|
) => self.remove_ids_from_caches(service_ids, characteristic_ids, descriptor_ids),
|
||||||
BluetoothRequest::IsRepresentedDeviceNull(id, sender) => {
|
BluetoothRequest::IsRepresentedDeviceNull(id, sender) => {
|
||||||
let _ = sender.send(!self.device_is_cached(&id));
|
let _ = sender.send(!self.device_is_cached(&id));
|
||||||
},
|
},
|
||||||
|
@ -266,9 +273,7 @@ impl BluetoothManager {
|
||||||
BluetoothRequest::MatchesFilter(id, filters, sender) => {
|
BluetoothRequest::MatchesFilter(id, filters, sender) => {
|
||||||
let _ = sender.send(self.device_matches_filter(&id, &filters));
|
let _ = sender.send(self.device_matches_filter(&id, &filters));
|
||||||
},
|
},
|
||||||
BluetoothRequest::Exit => {
|
BluetoothRequest::Exit => break,
|
||||||
break
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,10 +297,12 @@ impl BluetoothManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_ids_from_caches(&mut self,
|
fn remove_ids_from_caches(
|
||||||
service_ids: Vec<String>,
|
&mut self,
|
||||||
characteristic_ids: Vec<String>,
|
service_ids: Vec<String>,
|
||||||
descriptor_ids: Vec<String>) {
|
characteristic_ids: Vec<String>,
|
||||||
|
descriptor_ids: Vec<String>,
|
||||||
|
) {
|
||||||
for id in service_ids {
|
for id in service_ids {
|
||||||
self.cached_services.remove(&id);
|
self.cached_services.remove(&id);
|
||||||
self.service_to_device.remove(&id);
|
self.service_to_device.remove(&id);
|
||||||
|
@ -315,7 +322,10 @@ impl BluetoothManager {
|
||||||
// Adapter
|
// Adapter
|
||||||
|
|
||||||
pub 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());
|
let adapter_valid = self
|
||||||
|
.adapter
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |a| a.get_address().is_ok());
|
||||||
if !adapter_valid {
|
if !adapter_valid {
|
||||||
self.adapter = BluetoothAdapter::init().ok();
|
self.adapter = BluetoothAdapter::init().ok();
|
||||||
}
|
}
|
||||||
|
@ -344,13 +354,14 @@ impl BluetoothManager {
|
||||||
// Device
|
// Device
|
||||||
|
|
||||||
fn get_and_cache_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec<BluetoothDevice> {
|
fn get_and_cache_devices(&mut self, adapter: &mut BluetoothAdapter) -> Vec<BluetoothDevice> {
|
||||||
let devices = adapter.get_devices().unwrap_or(vec!());
|
let devices = adapter.get_devices().unwrap_or(vec![]);
|
||||||
for device in &devices {
|
for device in &devices {
|
||||||
if let Ok(address) = device.get_address() {
|
if let Ok(address) = device.get_address() {
|
||||||
if !self.address_to_id.contains_key(&address) {
|
if !self.address_to_id.contains_key(&address) {
|
||||||
let generated_id = self.generate_device_id();
|
let generated_id = self.generate_device_id();
|
||||||
self.address_to_id.insert(address, generated_id.clone());
|
self.address_to_id.insert(address, generated_id.clone());
|
||||||
self.cached_devices.insert(generated_id.clone(), device.clone());
|
self.cached_devices
|
||||||
|
.insert(generated_id.clone(), device.clone());
|
||||||
self.allowed_services.insert(generated_id, HashSet::new());
|
self.allowed_services.insert(generated_id, HashSet::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,14 +369,22 @@ impl BluetoothManager {
|
||||||
self.cached_devices.iter().map(|(_, d)| d.clone()).collect()
|
self.cached_devices.iter().map(|(_, d)| d.clone()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_device(&mut self, adapter: &mut BluetoothAdapter, device_id: &str) -> Option<&BluetoothDevice> {
|
fn get_device(
|
||||||
|
&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
device_id: &str,
|
||||||
|
) -> Option<&BluetoothDevice> {
|
||||||
return_if_cached!(self.cached_devices, device_id);
|
return_if_cached!(self.cached_devices, device_id);
|
||||||
self.get_and_cache_devices(adapter);
|
self.get_and_cache_devices(adapter);
|
||||||
return_if_cached!(self.cached_devices, device_id);
|
return_if_cached!(self.cached_devices, device_id);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_device(&mut self, devices: Vec<BluetoothDevice>, adapter: &BluetoothAdapter) -> Option<String> {
|
fn select_device(
|
||||||
|
&mut self,
|
||||||
|
devices: Vec<BluetoothDevice>,
|
||||||
|
adapter: &BluetoothAdapter,
|
||||||
|
) -> Option<String> {
|
||||||
if is_mock_adapter(adapter) || opts::get().headless {
|
if is_mock_adapter(adapter) || opts::get().headless {
|
||||||
for device in &devices {
|
for device in &devices {
|
||||||
if let Ok(address) = device.get_address() {
|
if let Ok(address) = device.get_address() {
|
||||||
|
@ -375,14 +394,19 @@ impl BluetoothManager {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dialog_rows: Vec<String> = vec!();
|
let mut dialog_rows: Vec<String> = vec![];
|
||||||
for device in devices {
|
for device in devices {
|
||||||
dialog_rows.extend_from_slice(&[device.get_address().unwrap_or("".to_string()),
|
dialog_rows.extend_from_slice(&[
|
||||||
device.get_name().unwrap_or("".to_string())]);
|
device.get_address().unwrap_or("".to_string()),
|
||||||
|
device.get_name().unwrap_or("".to_string()),
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
||||||
let msg = (None, EmbedderMsg::GetSelectedBluetoothDevice(dialog_rows, ipc_sender));
|
let msg = (
|
||||||
|
None,
|
||||||
|
EmbedderMsg::GetSelectedBluetoothDevice(dialog_rows, ipc_sender),
|
||||||
|
);
|
||||||
self.embedder_proxy.send(msg);
|
self.embedder_proxy.send(msg);
|
||||||
|
|
||||||
match ipc_receiver.recv() {
|
match ipc_receiver.recv() {
|
||||||
|
@ -390,7 +414,7 @@ impl BluetoothManager {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Failed to receive files from embedder ({}).", e);
|
warn!("Failed to receive files from embedder ({}).", e);
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,13 +436,15 @@ impl BluetoothManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_is_cached(&self, device_id: &str) -> bool {
|
fn device_is_cached(&self, device_id: &str) -> bool {
|
||||||
self.cached_devices.contains_key(device_id) && self.address_to_id.values().any(|v| v == device_id)
|
self.cached_devices.contains_key(device_id) &&
|
||||||
|
self.address_to_id.values().any(|v| v == device_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn device_matches_filter(&mut self,
|
fn device_matches_filter(
|
||||||
device_id: &str,
|
&mut self,
|
||||||
filters: &BluetoothScanfilterSequence)
|
device_id: &str,
|
||||||
-> BluetoothResult<bool> {
|
filters: &BluetoothScanfilterSequence,
|
||||||
|
) -> BluetoothResult<bool> {
|
||||||
let mut adapter = self.get_adapter()?;
|
let mut adapter = self.get_adapter()?;
|
||||||
match self.get_device(&mut adapter, device_id) {
|
match self.get_device(&mut adapter, device_id) {
|
||||||
Some(ref device) => Ok(matches_filters(device, filters)),
|
Some(ref device) => Ok(matches_filters(device, filters)),
|
||||||
|
@ -428,27 +454,36 @@ impl BluetoothManager {
|
||||||
|
|
||||||
// Service
|
// Service
|
||||||
|
|
||||||
fn get_and_cache_gatt_services(&mut self,
|
fn get_and_cache_gatt_services(
|
||||||
adapter: &mut BluetoothAdapter,
|
&mut self,
|
||||||
device_id: &str)
|
adapter: &mut BluetoothAdapter,
|
||||||
-> Vec<BluetoothGATTService> {
|
device_id: &str,
|
||||||
|
) -> Vec<BluetoothGATTService> {
|
||||||
let mut services = match self.get_device(adapter, device_id) {
|
let mut services = match self.get_device(adapter, device_id) {
|
||||||
Some(d) => d.get_gatt_services().unwrap_or(vec!()),
|
Some(d) => d.get_gatt_services().unwrap_or(vec![]),
|
||||||
None => vec!(),
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
services.retain(|s| !uuid_is_blocklisted(&s.get_uuid().unwrap_or(String::new()), Blocklist::All) &&
|
services.retain(|s| {
|
||||||
self.allowed_services
|
!uuid_is_blocklisted(&s.get_uuid().unwrap_or(String::new()), Blocklist::All) &&
|
||||||
.get(device_id)
|
self.allowed_services.get(device_id).map_or(false, |uuids| {
|
||||||
.map_or(false, |uuids| uuids.contains(&s.get_uuid().unwrap_or(String::new()))));
|
uuids.contains(&s.get_uuid().unwrap_or(String::new()))
|
||||||
|
})
|
||||||
|
});
|
||||||
for service in &services {
|
for service in &services {
|
||||||
self.cached_services.insert(service.get_id(), service.clone());
|
self.cached_services
|
||||||
self.service_to_device.insert(service.get_id(), device_id.to_owned());
|
.insert(service.get_id(), service.clone());
|
||||||
|
self.service_to_device
|
||||||
|
.insert(service.get_id(), device_id.to_owned());
|
||||||
}
|
}
|
||||||
services
|
services
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_gatt_service(&mut self, adapter: &mut BluetoothAdapter, service_id: &str) -> Option<&BluetoothGATTService> {
|
fn get_gatt_service(
|
||||||
|
&mut self,
|
||||||
|
adapter: &mut BluetoothAdapter,
|
||||||
|
service_id: &str,
|
||||||
|
) -> Option<&BluetoothGATTService> {
|
||||||
return_if_cached!(self.cached_services, service_id);
|
return_if_cached!(self.cached_services, service_id);
|
||||||
let device_id = self.service_to_device.get(service_id)?.clone();
|
let device_id = self.service_to_device.get(service_id)?.clone();
|
||||||
self.get_and_cache_gatt_services(adapter, &device_id);
|
self.get_and_cache_gatt_services(adapter, &device_id);
|
||||||
|
@ -457,34 +492,44 @@ impl BluetoothManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn service_is_cached(&self, service_id: &str) -> bool {
|
fn service_is_cached(&self, service_id: &str) -> bool {
|
||||||
self.cached_services.contains_key(service_id) && self.service_to_device.contains_key(service_id)
|
self.cached_services.contains_key(service_id) &&
|
||||||
|
self.service_to_device.contains_key(service_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Characteristic
|
// Characteristic
|
||||||
|
|
||||||
fn get_and_cache_gatt_characteristics(&mut self,
|
fn get_and_cache_gatt_characteristics(
|
||||||
adapter: &mut BluetoothAdapter,
|
&mut self,
|
||||||
service_id: &str)
|
adapter: &mut BluetoothAdapter,
|
||||||
-> Vec<BluetoothGATTCharacteristic> {
|
service_id: &str,
|
||||||
|
) -> Vec<BluetoothGATTCharacteristic> {
|
||||||
let mut characteristics = match self.get_gatt_service(adapter, service_id) {
|
let mut characteristics = match self.get_gatt_service(adapter, service_id) {
|
||||||
Some(s) => s.get_gatt_characteristics().unwrap_or(vec!()),
|
Some(s) => s.get_gatt_characteristics().unwrap_or(vec![]),
|
||||||
None => vec!(),
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
characteristics.retain(|c| !uuid_is_blocklisted(&c.get_uuid().unwrap_or(String::new()), Blocklist::All));
|
characteristics.retain(|c| {
|
||||||
|
!uuid_is_blocklisted(&c.get_uuid().unwrap_or(String::new()), Blocklist::All)
|
||||||
|
});
|
||||||
for characteristic in &characteristics {
|
for characteristic in &characteristics {
|
||||||
self.cached_characteristics.insert(characteristic.get_id(), characteristic.clone());
|
self.cached_characteristics
|
||||||
self.characteristic_to_service.insert(characteristic.get_id(), service_id.to_owned());
|
.insert(characteristic.get_id(), characteristic.clone());
|
||||||
|
self.characteristic_to_service
|
||||||
|
.insert(characteristic.get_id(), service_id.to_owned());
|
||||||
}
|
}
|
||||||
characteristics
|
characteristics
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_gatt_characteristic(&mut self,
|
fn get_gatt_characteristic(
|
||||||
adapter: &mut BluetoothAdapter,
|
&mut self,
|
||||||
characteristic_id: &str)
|
adapter: &mut BluetoothAdapter,
|
||||||
-> Option<&BluetoothGATTCharacteristic> {
|
characteristic_id: &str,
|
||||||
|
) -> Option<&BluetoothGATTCharacteristic> {
|
||||||
return_if_cached!(self.cached_characteristics, characteristic_id);
|
return_if_cached!(self.cached_characteristics, characteristic_id);
|
||||||
let service_id = self.characteristic_to_service.get(characteristic_id)?.clone();
|
let service_id = self
|
||||||
|
.characteristic_to_service
|
||||||
|
.get(characteristic_id)?
|
||||||
|
.clone();
|
||||||
self.get_and_cache_gatt_characteristics(adapter, &service_id);
|
self.get_and_cache_gatt_characteristics(adapter, &service_id);
|
||||||
return_if_cached!(self.cached_characteristics, characteristic_id);
|
return_if_cached!(self.cached_characteristics, characteristic_id);
|
||||||
None
|
None
|
||||||
|
@ -492,7 +537,7 @@ impl BluetoothManager {
|
||||||
|
|
||||||
fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> Flags {
|
fn get_characteristic_properties(&self, characteristic: &BluetoothGATTCharacteristic) -> Flags {
|
||||||
let mut props: Flags = Flags::empty();
|
let mut props: Flags = Flags::empty();
|
||||||
let flags = characteristic.get_flags().unwrap_or(vec!());
|
let flags = characteristic.get_flags().unwrap_or(vec![]);
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
match flag.as_ref() {
|
match flag.as_ref() {
|
||||||
"broadcast" => props.insert(Flags::BROADCAST),
|
"broadcast" => props.insert(Flags::BROADCAST),
|
||||||
|
@ -512,34 +557,44 @@ impl BluetoothManager {
|
||||||
|
|
||||||
fn characteristic_is_cached(&self, characteristic_id: &str) -> bool {
|
fn characteristic_is_cached(&self, characteristic_id: &str) -> bool {
|
||||||
self.cached_characteristics.contains_key(characteristic_id) &&
|
self.cached_characteristics.contains_key(characteristic_id) &&
|
||||||
self.characteristic_to_service.contains_key(characteristic_id)
|
self.characteristic_to_service
|
||||||
|
.contains_key(characteristic_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Descriptor
|
// Descriptor
|
||||||
|
|
||||||
fn get_and_cache_gatt_descriptors(&mut self,
|
fn get_and_cache_gatt_descriptors(
|
||||||
adapter: &mut BluetoothAdapter,
|
&mut self,
|
||||||
characteristic_id: &str)
|
adapter: &mut BluetoothAdapter,
|
||||||
-> Vec<BluetoothGATTDescriptor> {
|
characteristic_id: &str,
|
||||||
|
) -> Vec<BluetoothGATTDescriptor> {
|
||||||
let mut descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) {
|
let mut descriptors = match self.get_gatt_characteristic(adapter, characteristic_id) {
|
||||||
Some(c) => c.get_gatt_descriptors().unwrap_or(vec!()),
|
Some(c) => c.get_gatt_descriptors().unwrap_or(vec![]),
|
||||||
None => vec!(),
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
descriptors.retain(|d| !uuid_is_blocklisted(&d.get_uuid().unwrap_or(String::new()), Blocklist::All));
|
descriptors.retain(|d| {
|
||||||
|
!uuid_is_blocklisted(&d.get_uuid().unwrap_or(String::new()), Blocklist::All)
|
||||||
|
});
|
||||||
for descriptor in &descriptors {
|
for descriptor in &descriptors {
|
||||||
self.cached_descriptors.insert(descriptor.get_id(), descriptor.clone());
|
self.cached_descriptors
|
||||||
self.descriptor_to_characteristic.insert(descriptor.get_id(), characteristic_id.to_owned());
|
.insert(descriptor.get_id(), descriptor.clone());
|
||||||
|
self.descriptor_to_characteristic
|
||||||
|
.insert(descriptor.get_id(), characteristic_id.to_owned());
|
||||||
}
|
}
|
||||||
descriptors
|
descriptors
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_gatt_descriptor(&mut self,
|
fn get_gatt_descriptor(
|
||||||
adapter: &mut BluetoothAdapter,
|
&mut self,
|
||||||
descriptor_id: &str)
|
adapter: &mut BluetoothAdapter,
|
||||||
-> Option<&BluetoothGATTDescriptor> {
|
descriptor_id: &str,
|
||||||
|
) -> Option<&BluetoothGATTDescriptor> {
|
||||||
return_if_cached!(self.cached_descriptors, descriptor_id);
|
return_if_cached!(self.cached_descriptors, descriptor_id);
|
||||||
let characteristic_id = self.descriptor_to_characteristic.get(descriptor_id)?.clone();
|
let characteristic_id = self
|
||||||
|
.descriptor_to_characteristic
|
||||||
|
.get(descriptor_id)?
|
||||||
|
.clone();
|
||||||
self.get_and_cache_gatt_descriptors(adapter, &characteristic_id);
|
self.get_and_cache_gatt_descriptors(adapter, &characteristic_id);
|
||||||
return_if_cached!(self.cached_descriptors, descriptor_id);
|
return_if_cached!(self.cached_descriptors, descriptor_id);
|
||||||
None
|
None
|
||||||
|
@ -548,9 +603,7 @@ impl BluetoothManager {
|
||||||
// Methods
|
// Methods
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
|
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
|
||||||
fn request_device(&mut self,
|
fn request_device(&mut self, options: RequestDeviceoptions) -> BluetoothResponseResult {
|
||||||
options: RequestDeviceoptions)
|
|
||||||
-> BluetoothResponseResult {
|
|
||||||
// Step 6.
|
// Step 6.
|
||||||
let mut adapter = self.get_adapter()?;
|
let mut adapter = self.get_adapter()?;
|
||||||
|
|
||||||
|
@ -569,9 +622,10 @@ impl BluetoothManager {
|
||||||
|
|
||||||
// Step 8.
|
// Step 8.
|
||||||
if !options.is_accepting_all_devices() {
|
if !options.is_accepting_all_devices() {
|
||||||
matched_devices = matched_devices.into_iter()
|
matched_devices = matched_devices
|
||||||
.filter(|d| matches_filters(d, options.get_filters()))
|
.into_iter()
|
||||||
.collect();
|
.filter(|d| matches_filters(d, options.get_filters()))
|
||||||
|
.collect();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9.
|
// Step 9.
|
||||||
|
@ -623,7 +677,7 @@ impl BluetoothManager {
|
||||||
thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS));
|
thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// TODO: Step 5.1.4: Use the exchange MTU procedure.
|
// TODO: Step 5.1.4: Use the exchange MTU procedure.
|
||||||
}
|
}
|
||||||
// Step 5.1.3.
|
// Step 5.1.3.
|
||||||
return Err(BluetoothError::Network);
|
return Err(BluetoothError::Network);
|
||||||
|
@ -655,12 +709,13 @@ impl BluetoothManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
|
// https://webbluetoothcg.github.io/web-bluetooth/#getgattchildren
|
||||||
fn get_gatt_children(&mut self,
|
fn get_gatt_children(
|
||||||
id: String,
|
&mut self,
|
||||||
uuid: Option<String>,
|
id: String,
|
||||||
single: bool,
|
uuid: Option<String>,
|
||||||
child_type: GATTType)
|
single: bool,
|
||||||
-> BluetoothResponseResult {
|
child_type: GATTType,
|
||||||
|
) -> BluetoothResponseResult {
|
||||||
let mut adapter = self.get_adapter()?;
|
let mut adapter = self.get_adapter()?;
|
||||||
match child_type {
|
match child_type {
|
||||||
GATTType::PrimaryService => {
|
GATTType::PrimaryService => {
|
||||||
|
@ -670,7 +725,11 @@ impl BluetoothManager {
|
||||||
}
|
}
|
||||||
// Step 6.
|
// Step 6.
|
||||||
if let Some(ref uuid) = uuid {
|
if let Some(ref uuid) = uuid {
|
||||||
if !self.allowed_services.get(&id).map_or(false, |s| s.contains(uuid)) {
|
if !self
|
||||||
|
.allowed_services
|
||||||
|
.get(&id)
|
||||||
|
.map_or(false, |s| s.contains(uuid))
|
||||||
|
{
|
||||||
return Err(BluetoothError::Security);
|
return Err(BluetoothError::Security);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -678,17 +737,15 @@ impl BluetoothManager {
|
||||||
if let Some(uuid) = uuid {
|
if let Some(uuid) = uuid {
|
||||||
services.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
services.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
||||||
}
|
}
|
||||||
let mut services_vec = vec!();
|
let mut services_vec = vec![];
|
||||||
for service in services {
|
for service in services {
|
||||||
if service.is_primary().unwrap_or(false) {
|
if service.is_primary().unwrap_or(false) {
|
||||||
if let Ok(uuid) = service.get_uuid() {
|
if let Ok(uuid) = service.get_uuid() {
|
||||||
services_vec.push(
|
services_vec.push(BluetoothServiceMsg {
|
||||||
BluetoothServiceMsg {
|
uuid: uuid,
|
||||||
uuid: uuid,
|
is_primary: true,
|
||||||
is_primary: true,
|
instance_id: service.get_id(),
|
||||||
instance_id: service.get_id(),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,29 +762,30 @@ impl BluetoothManager {
|
||||||
return Err(BluetoothError::InvalidState);
|
return Err(BluetoothError::InvalidState);
|
||||||
}
|
}
|
||||||
// Step 6.
|
// Step 6.
|
||||||
let mut characteristics = self.get_and_cache_gatt_characteristics(&mut adapter, &id);
|
let mut characteristics =
|
||||||
|
self.get_and_cache_gatt_characteristics(&mut adapter, &id);
|
||||||
if let Some(uuid) = uuid {
|
if let Some(uuid) = uuid {
|
||||||
characteristics.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
characteristics.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
||||||
}
|
}
|
||||||
let mut characteristics_vec = vec!();
|
let mut characteristics_vec = vec![];
|
||||||
for characteristic in characteristics {
|
for characteristic in characteristics {
|
||||||
if let Ok(uuid) = characteristic.get_uuid() {
|
if let Ok(uuid) = characteristic.get_uuid() {
|
||||||
let properties = self.get_characteristic_properties(&characteristic);
|
let properties = self.get_characteristic_properties(&characteristic);
|
||||||
characteristics_vec.push(
|
characteristics_vec.push(BluetoothCharacteristicMsg {
|
||||||
BluetoothCharacteristicMsg {
|
uuid: uuid,
|
||||||
uuid: uuid,
|
instance_id: characteristic.get_id(),
|
||||||
instance_id: characteristic.get_id(),
|
broadcast: properties.contains(Flags::BROADCAST),
|
||||||
broadcast: properties.contains(Flags::BROADCAST),
|
read: properties.contains(Flags::READ),
|
||||||
read: properties.contains(Flags::READ),
|
write_without_response: properties
|
||||||
write_without_response: properties.contains(Flags::WRITE_WITHOUT_RESPONSE),
|
.contains(Flags::WRITE_WITHOUT_RESPONSE),
|
||||||
write: properties.contains(Flags::WRITE),
|
write: properties.contains(Flags::WRITE),
|
||||||
notify: properties.contains(Flags::NOTIFY),
|
notify: properties.contains(Flags::NOTIFY),
|
||||||
indicate: properties.contains(Flags::INDICATE),
|
indicate: properties.contains(Flags::INDICATE),
|
||||||
authenticated_signed_writes: properties.contains(Flags::AUTHENTICATED_SIGNED_WRITES),
|
authenticated_signed_writes: properties
|
||||||
reliable_write: properties.contains(Flags::RELIABLE_WRITE),
|
.contains(Flags::AUTHENTICATED_SIGNED_WRITES),
|
||||||
writable_auxiliaries: properties.contains(Flags::WRITABLE_AUXILIARIES),
|
reliable_write: properties.contains(Flags::RELIABLE_WRITE),
|
||||||
}
|
writable_auxiliaries: properties.contains(Flags::WRITABLE_AUXILIARIES),
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,7 +794,10 @@ impl BluetoothManager {
|
||||||
return Err(BluetoothError::NotFound);
|
return Err(BluetoothError::NotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(BluetoothResponse::GetCharacteristics(characteristics_vec, single));
|
return Ok(BluetoothResponse::GetCharacteristics(
|
||||||
|
characteristics_vec,
|
||||||
|
single,
|
||||||
|
));
|
||||||
},
|
},
|
||||||
GATTType::IncludedService => {
|
GATTType::IncludedService => {
|
||||||
// Step 5.
|
// Step 5.
|
||||||
|
@ -752,17 +813,15 @@ impl BluetoothManager {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => return Err(BluetoothError::NotFound),
|
None => return Err(BluetoothError::NotFound),
|
||||||
};
|
};
|
||||||
let services = primary_service.get_includes(device).unwrap_or(vec!());
|
let services = primary_service.get_includes(device).unwrap_or(vec![]);
|
||||||
let mut services_vec = vec!();
|
let mut services_vec = vec![];
|
||||||
for service in services {
|
for service in services {
|
||||||
if let Ok(service_uuid) = service.get_uuid() {
|
if let Ok(service_uuid) = service.get_uuid() {
|
||||||
services_vec.push(
|
services_vec.push(BluetoothServiceMsg {
|
||||||
BluetoothServiceMsg {
|
uuid: service_uuid,
|
||||||
uuid: service_uuid,
|
is_primary: service.is_primary().unwrap_or(false),
|
||||||
is_primary: service.is_primary().unwrap_or(false),
|
instance_id: service.get_id(),
|
||||||
instance_id: service.get_id(),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(uuid) = uuid {
|
if let Some(uuid) = uuid {
|
||||||
|
@ -787,15 +846,13 @@ impl BluetoothManager {
|
||||||
if let Some(uuid) = uuid {
|
if let Some(uuid) = uuid {
|
||||||
descriptors.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
descriptors.retain(|ref e| e.get_uuid().unwrap_or(String::new()) == uuid);
|
||||||
}
|
}
|
||||||
let mut descriptors_vec = vec!();
|
let mut descriptors_vec = vec![];
|
||||||
for descriptor in descriptors {
|
for descriptor in descriptors {
|
||||||
if let Ok(uuid) = descriptor.get_uuid() {
|
if let Ok(uuid) = descriptor.get_uuid() {
|
||||||
descriptors_vec.push(
|
descriptors_vec.push(BluetoothDescriptorMsg {
|
||||||
BluetoothDescriptorMsg {
|
uuid: uuid,
|
||||||
uuid: uuid,
|
instance_id: descriptor.get_id(),
|
||||||
instance_id: descriptor.get_id(),
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -816,15 +873,17 @@ impl BluetoothManager {
|
||||||
let mut adapter = self.get_adapter()?;
|
let mut adapter = self.get_adapter()?;
|
||||||
|
|
||||||
// (Characteristic) Step 5.3.
|
// (Characteristic) Step 5.3.
|
||||||
let mut value = self.get_gatt_characteristic(&mut adapter, &id)
|
let mut value = self
|
||||||
.map(|c| c.read_value().unwrap_or(vec![]));
|
.get_gatt_characteristic(&mut adapter, &id)
|
||||||
|
.map(|c| c.read_value().unwrap_or(vec![]));
|
||||||
|
|
||||||
// (Characteristic) TODO: Step 5.4: Handle all the errors returned from the read_value call.
|
// (Characteristic) TODO: Step 5.4: Handle all the errors returned from the read_value call.
|
||||||
|
|
||||||
// (Descriptor) Step 5.2.
|
// (Descriptor) Step 5.2.
|
||||||
if value.is_none() {
|
if value.is_none() {
|
||||||
value = self.get_gatt_descriptor(&mut adapter, &id)
|
value = self
|
||||||
.map(|d| d.read_value().unwrap_or(vec![]));
|
.get_gatt_descriptor(&mut adapter, &id)
|
||||||
|
.map(|d| d.read_value().unwrap_or(vec![]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Descriptor) TODO: Step 5.3: Handle all the errors returned from the read_value call.
|
// (Descriptor) TODO: Step 5.3: Handle all the errors returned from the read_value call.
|
||||||
|
@ -848,15 +907,17 @@ impl BluetoothManager {
|
||||||
let mut adapter = self.get_adapter()?;
|
let mut adapter = self.get_adapter()?;
|
||||||
|
|
||||||
// (Characteristic) Step 7.3.
|
// (Characteristic) Step 7.3.
|
||||||
let mut result = self.get_gatt_characteristic(&mut adapter, &id)
|
let mut result = self
|
||||||
.map(|c| c.write_value(value.clone()));
|
.get_gatt_characteristic(&mut adapter, &id)
|
||||||
|
.map(|c| c.write_value(value.clone()));
|
||||||
|
|
||||||
// (Characteristic) TODO: Step 7.4: Handle all the errors returned from the write_value call.
|
// (Characteristic) TODO: Step 7.4: Handle all the errors returned from the write_value call.
|
||||||
|
|
||||||
// (Descriptor) Step 7.2.
|
// (Descriptor) Step 7.2.
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
result = self.get_gatt_descriptor(&mut adapter, &id)
|
result = self
|
||||||
.map(|d| d.write_value(value.clone()));
|
.get_gatt_descriptor(&mut adapter, &id)
|
||||||
|
.map(|d| d.write_value(value.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// (Descriptor) TODO: Step 7.3: Handle all the errors returned from the write_value call.
|
// (Descriptor) TODO: Step 7.3: Handle all the errors returned from the write_value call.
|
||||||
|
@ -921,6 +982,8 @@ impl BluetoothManager {
|
||||||
|
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-getavailability
|
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetooth-getavailability
|
||||||
fn get_availability(&mut self) -> BluetoothResponseResult {
|
fn get_availability(&mut self) -> BluetoothResponseResult {
|
||||||
Ok(BluetoothResponse::GetAvailability(self.get_adapter().is_ok()))
|
Ok(BluetoothResponse::GetAvailability(
|
||||||
|
self.get_adapter().is_ok(),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,8 @@ const UNICODE_DEVICE_ADAPTER: &'static str = "UnicodeDeviceAdapter";
|
||||||
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=205
|
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=205
|
||||||
const MISSING_SERVICE_HEART_RATE_ADAPTER: &'static str = "MissingServiceHeartRateAdapter";
|
const MISSING_SERVICE_HEART_RATE_ADAPTER: &'static str = "MissingServiceHeartRateAdapter";
|
||||||
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=219
|
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=219
|
||||||
const MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER: &'static str = "MissingCharacteristicHeartRateAdapter";
|
const MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER: &'static str =
|
||||||
|
"MissingCharacteristicHeartRateAdapter";
|
||||||
const MISSING_DESCRIPTOR_HEART_RATE_ADAPTER: &'static str = "MissingDescriptorHeartRateAdapter";
|
const MISSING_DESCRIPTOR_HEART_RATE_ADAPTER: &'static str = "MissingDescriptorHeartRateAdapter";
|
||||||
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=234
|
// https://cs.chromium.org/chromium/src/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h?l=234
|
||||||
const HEART_RATE_ADAPTER: &'static str = "HeartRateAdapter";
|
const HEART_RATE_ADAPTER: &'static str = "HeartRateAdapter";
|
||||||
|
@ -80,32 +81,38 @@ const HUMAN_INTERFACE_DEVICE_SERVICE_UUID: &'static str = "00001812-0000-1000-80
|
||||||
const TX_POWER_SERVICE_UUID: &'static str = "00001804-0000-1000-8000-00805f9b34fb";
|
const TX_POWER_SERVICE_UUID: &'static str = "00001804-0000-1000-8000-00805f9b34fb";
|
||||||
|
|
||||||
// Characteristic UUIDs
|
// Characteristic UUIDs
|
||||||
const BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID: &'static str = "bad1c9a2-9a5b-4015-8b60-1579bbbf2135";
|
const BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID: &'static str =
|
||||||
|
"bad1c9a2-9a5b-4015-8b60-1579bbbf2135";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
|
// viewer?attributeXmlFile=org.bluetooth.characteristic.body_sensor_location.xml
|
||||||
const BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID: &'static str = "00002a38-0000-1000-8000-00805f9b34fb";
|
const BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID: &'static str =
|
||||||
|
"00002a38-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.characteristic.gap.device_name.xml
|
// viewer?attributeXmlFile=org.bluetooth.characteristic.gap.device_name.xml
|
||||||
const DEVICE_NAME_CHARACTERISTIC_UUID: &'static str = "00002a00-0000-1000-8000-00805f9b34fb";
|
const DEVICE_NAME_CHARACTERISTIC_UUID: &'static str = "00002a00-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
|
// viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
|
||||||
const HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID: &'static str = "00002a37-0000-1000-8000-00805f9b34fb";
|
const HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID: &'static str =
|
||||||
|
"00002a37-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.characteristic.gap.peripheral_privacy_flag.xml
|
// viewer?attributeXmlFile=org.bluetooth.characteristic.gap.peripheral_privacy_flag.xml
|
||||||
const PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID: &'static str = "00002a02-0000-1000-8000-00805f9b34fb";
|
const PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID: &'static str =
|
||||||
|
"00002a02-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.characteristic.serial_number_string.xml
|
// viewer?attributeXmlFile=org.bluetooth.characteristic.serial_number_string.xml
|
||||||
const SERIAL_NUMBER_STRING_UUID: &'static str = "00002a25-0000-1000-8000-00805f9b34fb";
|
const SERIAL_NUMBER_STRING_UUID: &'static str = "00002a25-0000-1000-8000-00805f9b34fb";
|
||||||
|
|
||||||
// Descriptor UUIDs
|
// Descriptor UUIDs
|
||||||
const BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID: &'static str = "aaaaaaaa-aaaa-1181-0510-810819516110";
|
const BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID: &'static str =
|
||||||
|
"aaaaaaaa-aaaa-1181-0510-810819516110";
|
||||||
const BLOCKLIST_DESCRIPTOR_UUID: &'static str = "07711111-6104-0970-7011-1107105110aa";
|
const BLOCKLIST_DESCRIPTOR_UUID: &'static str = "07711111-6104-0970-7011-1107105110aa";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_user_description.xml
|
// viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.characteristic_user_description.xml
|
||||||
const CHARACTERISTIC_USER_DESCRIPTION_UUID: &'static str = "00002901-0000-1000-8000-00805f9b34fb";
|
const CHARACTERISTIC_USER_DESCRIPTION_UUID: &'static str = "00002901-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
// viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
|
||||||
const CLIENT_CHARACTERISTIC_CONFIGURATION_UUID: &'static str = "00002902-0000-1000-8000-00805f9b34fb";
|
const CLIENT_CHARACTERISTIC_CONFIGURATION_UUID: &'static str =
|
||||||
|
"00002902-0000-1000-8000-00805f9b34fb";
|
||||||
// https://www.bluetooth.com/specifications/gatt/
|
// https://www.bluetooth.com/specifications/gatt/
|
||||||
// viewer?attributeXmlFile=org.bluetooth.descriptor.number_of_digitals.xml
|
// viewer?attributeXmlFile=org.bluetooth.descriptor.number_of_digitals.xml
|
||||||
const NUMBER_OF_DIGITALS_UUID: &'static str = "00002909-0000-1000-8000-00805f9b34fb";
|
const NUMBER_OF_DIGITALS_UUID: &'static str = "00002909-0000-1000-8000-00805f9b34fb";
|
||||||
|
@ -117,12 +124,12 @@ fn generate_id() -> Uuid {
|
||||||
let mut generated = false;
|
let mut generated = false;
|
||||||
while !generated {
|
while !generated {
|
||||||
id = Uuid::new_v4();
|
id = Uuid::new_v4();
|
||||||
CACHED_IDS.with(|cache|
|
CACHED_IDS.with(|cache| {
|
||||||
if !cache.borrow().contains(&id) {
|
if !cache.borrow().contains(&id) {
|
||||||
cache.borrow_mut().insert(id.clone());
|
cache.borrow_mut().insert(id.clone());
|
||||||
generated = true;
|
generated = true;
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
@ -136,10 +143,11 @@ fn set_adapter(adapter: &BluetoothAdapter, adapter_name: String) -> Result<(), B
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Device
|
// Create Device
|
||||||
fn create_device(adapter: &BluetoothAdapter,
|
fn create_device(
|
||||||
name: String,
|
adapter: &BluetoothAdapter,
|
||||||
address: String)
|
name: String,
|
||||||
-> Result<BluetoothDevice, Box<Error>> {
|
address: String,
|
||||||
|
) -> Result<BluetoothDevice, Box<Error>> {
|
||||||
let device = BluetoothDevice::create_mock_device(adapter.clone(), generate_id().to_string())?;
|
let device = BluetoothDevice::create_mock_device(adapter.clone(), generate_id().to_string())?;
|
||||||
device.set_name(Some(name))?;
|
device.set_name(Some(name))?;
|
||||||
device.set_address(address)?;
|
device.set_address(address)?;
|
||||||
|
@ -148,162 +156,192 @@ fn create_device(adapter: &BluetoothAdapter,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Device with UUIDs
|
// Create Device with UUIDs
|
||||||
fn create_device_with_uuids(adapter: &BluetoothAdapter,
|
fn create_device_with_uuids(
|
||||||
name: String,
|
adapter: &BluetoothAdapter,
|
||||||
address: String,
|
name: String,
|
||||||
uuids: Vec<String>)
|
address: String,
|
||||||
-> Result<BluetoothDevice, Box<Error>> {
|
uuids: Vec<String>,
|
||||||
|
) -> Result<BluetoothDevice, Box<Error>> {
|
||||||
let device = create_device(adapter, name, address)?;
|
let device = create_device(adapter, name, address)?;
|
||||||
device.set_uuids(uuids)?;
|
device.set_uuids(uuids)?;
|
||||||
Ok(device)
|
Ok(device)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Service
|
// Create Service
|
||||||
fn create_service(device: &BluetoothDevice,
|
fn create_service(
|
||||||
uuid: String)
|
device: &BluetoothDevice,
|
||||||
-> Result<BluetoothGATTService, Box<Error>> {
|
uuid: String,
|
||||||
let service = BluetoothGATTService::create_mock_service(device.clone(), generate_id().to_string())?;
|
) -> Result<BluetoothGATTService, Box<Error>> {
|
||||||
|
let service =
|
||||||
|
BluetoothGATTService::create_mock_service(device.clone(), generate_id().to_string())?;
|
||||||
service.set_uuid(uuid)?;
|
service.set_uuid(uuid)?;
|
||||||
Ok(service)
|
Ok(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Characteristic
|
// Create Characteristic
|
||||||
fn create_characteristic(service: &BluetoothGATTService,
|
fn create_characteristic(
|
||||||
uuid: String)
|
service: &BluetoothGATTService,
|
||||||
-> Result<BluetoothGATTCharacteristic, Box<Error>> {
|
uuid: String,
|
||||||
let characteristic =
|
) -> Result<BluetoothGATTCharacteristic, Box<Error>> {
|
||||||
BluetoothGATTCharacteristic::create_mock_characteristic(service.clone(), generate_id().to_string())?;
|
let characteristic = BluetoothGATTCharacteristic::create_mock_characteristic(
|
||||||
|
service.clone(),
|
||||||
|
generate_id().to_string(),
|
||||||
|
)?;
|
||||||
characteristic.set_uuid(uuid)?;
|
characteristic.set_uuid(uuid)?;
|
||||||
Ok(characteristic)
|
Ok(characteristic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Characteristic with value
|
// Create Characteristic with value
|
||||||
fn create_characteristic_with_value(service: &BluetoothGATTService,
|
fn create_characteristic_with_value(
|
||||||
uuid: String,
|
service: &BluetoothGATTService,
|
||||||
value: Vec<u8>)
|
uuid: String,
|
||||||
-> Result<BluetoothGATTCharacteristic, Box<Error>> {
|
value: Vec<u8>,
|
||||||
|
) -> Result<BluetoothGATTCharacteristic, Box<Error>> {
|
||||||
let characteristic = create_characteristic(service, uuid)?;
|
let characteristic = create_characteristic(service, uuid)?;
|
||||||
characteristic.set_value(value)?;
|
characteristic.set_value(value)?;
|
||||||
Ok(characteristic)
|
Ok(characteristic)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Descriptor
|
// Create Descriptor
|
||||||
fn create_descriptor(characteristic: &BluetoothGATTCharacteristic,
|
fn create_descriptor(
|
||||||
uuid: String)
|
characteristic: &BluetoothGATTCharacteristic,
|
||||||
-> Result<BluetoothGATTDescriptor, Box<Error>> {
|
uuid: String,
|
||||||
let descriptor =
|
) -> Result<BluetoothGATTDescriptor, Box<Error>> {
|
||||||
BluetoothGATTDescriptor::create_mock_descriptor(characteristic.clone(), generate_id().to_string())?;
|
let descriptor = BluetoothGATTDescriptor::create_mock_descriptor(
|
||||||
|
characteristic.clone(),
|
||||||
|
generate_id().to_string(),
|
||||||
|
)?;
|
||||||
descriptor.set_uuid(uuid)?;
|
descriptor.set_uuid(uuid)?;
|
||||||
Ok(descriptor)
|
Ok(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Descriptor with value
|
// Create Descriptor with value
|
||||||
fn create_descriptor_with_value(characteristic: &BluetoothGATTCharacteristic,
|
fn create_descriptor_with_value(
|
||||||
uuid: String,
|
characteristic: &BluetoothGATTCharacteristic,
|
||||||
value: Vec<u8>)
|
uuid: String,
|
||||||
-> Result<BluetoothGATTDescriptor, Box<Error>> {
|
value: Vec<u8>,
|
||||||
|
) -> Result<BluetoothGATTDescriptor, Box<Error>> {
|
||||||
let descriptor = create_descriptor(characteristic, uuid)?;
|
let descriptor = create_descriptor(characteristic, uuid)?;
|
||||||
descriptor.set_value(value)?;
|
descriptor.set_value(value)?;
|
||||||
Ok(descriptor)
|
Ok(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_heart_rate_service(device: &BluetoothDevice,
|
fn create_heart_rate_service(
|
||||||
empty: bool)
|
device: &BluetoothDevice,
|
||||||
-> Result<BluetoothGATTService, Box<Error>> {
|
empty: bool,
|
||||||
|
) -> Result<BluetoothGATTService, Box<Error>> {
|
||||||
// Heart Rate Service
|
// Heart Rate Service
|
||||||
let heart_rate_service = create_service(device, HEART_RATE_SERVICE_UUID.to_owned())?;
|
let heart_rate_service = create_service(device, HEART_RATE_SERVICE_UUID.to_owned())?;
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
return Ok(heart_rate_service)
|
return Ok(heart_rate_service);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heart Rate Measurement Characteristic
|
// Heart Rate Measurement Characteristic
|
||||||
let heart_rate_measurement_characteristic =
|
let heart_rate_measurement_characteristic = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service,
|
&heart_rate_service,
|
||||||
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
|
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![0])?;
|
vec![0],
|
||||||
heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string(),
|
)?;
|
||||||
READ_FLAG.to_string(),
|
heart_rate_measurement_characteristic.set_flags(vec![
|
||||||
WRITE_FLAG.to_string()])?;
|
NOTIFY_FLAG.to_string(),
|
||||||
|
READ_FLAG.to_string(),
|
||||||
|
WRITE_FLAG.to_string(),
|
||||||
|
])?;
|
||||||
|
|
||||||
// Body Sensor Location Characteristic 1
|
// Body Sensor Location Characteristic 1
|
||||||
let body_sensor_location_characteristic_1 =
|
let body_sensor_location_characteristic_1 = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service,
|
&heart_rate_service,
|
||||||
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![49])?;
|
vec![49],
|
||||||
body_sensor_location_characteristic_1.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
)?;
|
||||||
|
body_sensor_location_characteristic_1
|
||||||
|
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
// Body Sensor Location Characteristic 2
|
// Body Sensor Location Characteristic 2
|
||||||
let body_sensor_location_characteristic_2 =
|
let body_sensor_location_characteristic_2 = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service,
|
&heart_rate_service,
|
||||||
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![50])?;
|
vec![50],
|
||||||
body_sensor_location_characteristic_2.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
)?;
|
||||||
|
body_sensor_location_characteristic_2
|
||||||
|
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
Ok(heart_rate_service)
|
Ok(heart_rate_service)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_generic_access_service(device: &BluetoothDevice,
|
fn create_generic_access_service(
|
||||||
empty: bool)
|
device: &BluetoothDevice,
|
||||||
-> Result<BluetoothGATTService, Box<Error>> {
|
empty: bool,
|
||||||
|
) -> Result<BluetoothGATTService, Box<Error>> {
|
||||||
// Generic Access Service
|
// Generic Access Service
|
||||||
let generic_access_service =
|
let generic_access_service = create_service(device, GENERIC_ACCESS_SERVICE_UUID.to_owned())?;
|
||||||
create_service(device, GENERIC_ACCESS_SERVICE_UUID.to_owned())?;
|
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
return Ok(generic_access_service)
|
return Ok(generic_access_service);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Device Name Characteristic
|
// Device Name Characteristic
|
||||||
let device_name_characteristic =
|
let device_name_characteristic = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&generic_access_service,
|
&generic_access_service,
|
||||||
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
|
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
|
||||||
HEART_RATE_DEVICE_NAME.as_bytes().to_vec())?;
|
HEART_RATE_DEVICE_NAME.as_bytes().to_vec(),
|
||||||
|
)?;
|
||||||
device_name_characteristic.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
device_name_characteristic.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
// Number of Digitals descriptor
|
// Number of Digitals descriptor
|
||||||
let number_of_digitals_descriptor_1 =
|
let number_of_digitals_descriptor_1 = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&device_name_characteristic,
|
&device_name_characteristic,
|
||||||
NUMBER_OF_DIGITALS_UUID.to_owned(),
|
NUMBER_OF_DIGITALS_UUID.to_owned(),
|
||||||
vec![49])?;
|
vec![49],
|
||||||
|
)?;
|
||||||
number_of_digitals_descriptor_1.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
number_of_digitals_descriptor_1.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
let number_of_digitals_descriptor_2 =
|
let number_of_digitals_descriptor_2 = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&device_name_characteristic,
|
&device_name_characteristic,
|
||||||
NUMBER_OF_DIGITALS_UUID.to_owned(),
|
NUMBER_OF_DIGITALS_UUID.to_owned(),
|
||||||
vec![50])?;
|
vec![50],
|
||||||
|
)?;
|
||||||
number_of_digitals_descriptor_2.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
number_of_digitals_descriptor_2.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
// Characteristic User Description Descriptor
|
// Characteristic User Description Descriptor
|
||||||
let _characteristic_user_description =
|
let _characteristic_user_description = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&device_name_characteristic,
|
&device_name_characteristic,
|
||||||
CHARACTERISTIC_USER_DESCRIPTION_UUID.to_owned(),
|
CHARACTERISTIC_USER_DESCRIPTION_UUID.to_owned(),
|
||||||
HEART_RATE_DEVICE_NAME_DESCRIPTION.as_bytes().to_vec())?;
|
HEART_RATE_DEVICE_NAME_DESCRIPTION.as_bytes().to_vec(),
|
||||||
|
)?;
|
||||||
|
|
||||||
// Client Characteristic Configuration descriptor
|
// Client Characteristic Configuration descriptor
|
||||||
let _client_characteristic_configuration =
|
let _client_characteristic_configuration = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&device_name_characteristic,
|
&device_name_characteristic,
|
||||||
CLIENT_CHARACTERISTIC_CONFIGURATION_UUID.to_owned(),
|
CLIENT_CHARACTERISTIC_CONFIGURATION_UUID.to_owned(),
|
||||||
vec![0])?;
|
vec![0],
|
||||||
|
)?;
|
||||||
|
|
||||||
// Peripheral Privacy Flag Characteristic
|
// Peripheral Privacy Flag Characteristic
|
||||||
let peripheral_privacy_flag_characteristic =
|
let peripheral_privacy_flag_characteristic = create_characteristic(
|
||||||
create_characteristic(&generic_access_service, PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned())?;
|
&generic_access_service,
|
||||||
|
PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned(),
|
||||||
|
)?;
|
||||||
peripheral_privacy_flag_characteristic
|
peripheral_privacy_flag_characteristic
|
||||||
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
Ok(generic_access_service)
|
Ok(generic_access_service)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Heart Rate Device
|
// Create Heart Rate Device
|
||||||
fn create_heart_rate_device(adapter: &BluetoothAdapter,
|
fn create_heart_rate_device(
|
||||||
empty: bool)
|
adapter: &BluetoothAdapter,
|
||||||
-> Result<BluetoothDevice, Box<Error>> {
|
empty: bool,
|
||||||
|
) -> Result<BluetoothDevice, Box<Error>> {
|
||||||
// Heart Rate Device
|
// Heart Rate Device
|
||||||
let heart_rate_device =
|
let heart_rate_device = create_device_with_uuids(
|
||||||
create_device_with_uuids(adapter,
|
adapter,
|
||||||
HEART_RATE_DEVICE_NAME.to_owned(),
|
HEART_RATE_DEVICE_NAME.to_owned(),
|
||||||
HEART_RATE_DEVICE_ADDRESS.to_owned(),
|
HEART_RATE_DEVICE_ADDRESS.to_owned(),
|
||||||
vec![GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
vec![
|
||||||
HEART_RATE_SERVICE_UUID.to_owned()])?;
|
GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
||||||
|
HEART_RATE_SERVICE_UUID.to_owned(),
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
|
||||||
if empty {
|
if empty {
|
||||||
return Ok(heart_rate_device);
|
return Ok(heart_rate_device);
|
||||||
|
@ -318,30 +356,39 @@ fn create_heart_rate_device(adapter: &BluetoothAdapter,
|
||||||
Ok(heart_rate_device)
|
Ok(heart_rate_device)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_missing_characterisitc_heart_rate_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
fn create_missing_characterisitc_heart_rate_device(
|
||||||
|
adapter: &BluetoothAdapter,
|
||||||
|
) -> Result<(), Box<Error>> {
|
||||||
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
||||||
|
|
||||||
let _generic_access_service_empty = create_generic_access_service(&heart_rate_device_empty, true)?;
|
let _generic_access_service_empty =
|
||||||
|
create_generic_access_service(&heart_rate_device_empty, true)?;
|
||||||
|
|
||||||
let _heart_rate_service_empty = create_heart_rate_service(&heart_rate_device_empty, true)?;
|
let _heart_rate_service_empty = create_heart_rate_service(&heart_rate_device_empty, true)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_missing_descriptor_heart_rate_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
fn create_missing_descriptor_heart_rate_device(
|
||||||
|
adapter: &BluetoothAdapter,
|
||||||
|
) -> Result<(), Box<Error>> {
|
||||||
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
||||||
|
|
||||||
let generic_access_service_empty = create_generic_access_service(&heart_rate_device_empty, true)?;
|
let generic_access_service_empty =
|
||||||
|
create_generic_access_service(&heart_rate_device_empty, true)?;
|
||||||
|
|
||||||
let _device_name_characteristic =
|
let _device_name_characteristic = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&generic_access_service_empty,
|
&generic_access_service_empty,
|
||||||
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
|
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
|
||||||
HEART_RATE_DEVICE_NAME.as_bytes().to_vec())?;
|
HEART_RATE_DEVICE_NAME.as_bytes().to_vec(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let peripheral_privacy_flag_characteristic =
|
let peripheral_privacy_flag_characteristic = create_characteristic(
|
||||||
create_characteristic(&generic_access_service_empty,
|
&generic_access_service_empty,
|
||||||
PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned())?;
|
PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned(),
|
||||||
peripheral_privacy_flag_characteristic.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
)?;
|
||||||
|
peripheral_privacy_flag_characteristic
|
||||||
|
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
let _heart_rate_service = create_heart_rate_service(&heart_rate_device_empty, false)?;
|
let _heart_rate_service = create_heart_rate_service(&heart_rate_device_empty, false)?;
|
||||||
|
|
||||||
|
@ -351,9 +398,11 @@ fn create_missing_descriptor_heart_rate_device(adapter: &BluetoothAdapter) -> Re
|
||||||
fn create_two_heart_rate_services_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
fn create_two_heart_rate_services_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
||||||
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
||||||
|
|
||||||
heart_rate_device_empty.set_uuids(vec![GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
heart_rate_device_empty.set_uuids(vec![
|
||||||
HEART_RATE_SERVICE_UUID.to_owned(),
|
GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
||||||
HEART_RATE_SERVICE_UUID.to_owned()])?;
|
HEART_RATE_SERVICE_UUID.to_owned(),
|
||||||
|
HEART_RATE_SERVICE_UUID.to_owned(),
|
||||||
|
])?;
|
||||||
|
|
||||||
let _generic_access_service = create_generic_access_service(&heart_rate_device_empty, false)?;
|
let _generic_access_service = create_generic_access_service(&heart_rate_device_empty, false)?;
|
||||||
|
|
||||||
|
@ -361,73 +410,92 @@ fn create_two_heart_rate_services_device(adapter: &BluetoothAdapter) -> Result<(
|
||||||
|
|
||||||
let heart_rate_service_empty_2 = create_heart_rate_service(&heart_rate_device_empty, true)?;
|
let heart_rate_service_empty_2 = create_heart_rate_service(&heart_rate_device_empty, true)?;
|
||||||
|
|
||||||
let heart_rate_measurement_characteristic =
|
let heart_rate_measurement_characteristic = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service_empty_1,
|
&heart_rate_service_empty_1,
|
||||||
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
|
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![0])?;
|
vec![0],
|
||||||
|
)?;
|
||||||
heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()])?;
|
heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()])?;
|
||||||
|
|
||||||
let _body_sensor_location_characteristic_1 =
|
let _body_sensor_location_characteristic_1 = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service_empty_1,
|
&heart_rate_service_empty_1,
|
||||||
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![49])?;
|
vec![49],
|
||||||
|
)?;
|
||||||
|
|
||||||
let _body_sensor_location_characteristic_2 =
|
let _body_sensor_location_characteristic_2 = create_characteristic_with_value(
|
||||||
create_characteristic_with_value(&heart_rate_service_empty_2,
|
&heart_rate_service_empty_2,
|
||||||
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
|
||||||
vec![50])?;
|
vec![50],
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_blocklisted_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
fn create_blocklisted_device(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
||||||
let connectable_device =
|
let connectable_device = create_device_with_uuids(
|
||||||
create_device_with_uuids(adapter,
|
adapter,
|
||||||
CONNECTABLE_DEVICE_NAME.to_owned(),
|
CONNECTABLE_DEVICE_NAME.to_owned(),
|
||||||
CONNECTABLE_DEVICE_ADDRESS.to_owned(),
|
CONNECTABLE_DEVICE_ADDRESS.to_owned(),
|
||||||
vec![BLOCKLIST_TEST_SERVICE_UUID.to_owned(),
|
vec![
|
||||||
DEVICE_INFORMATION_UUID.to_owned(),
|
BLOCKLIST_TEST_SERVICE_UUID.to_owned(),
|
||||||
GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
DEVICE_INFORMATION_UUID.to_owned(),
|
||||||
HEART_RATE_SERVICE_UUID.to_owned(),
|
GENERIC_ACCESS_SERVICE_UUID.to_owned(),
|
||||||
HUMAN_INTERFACE_DEVICE_SERVICE_UUID.to_owned()])?;
|
HEART_RATE_SERVICE_UUID.to_owned(),
|
||||||
|
HUMAN_INTERFACE_DEVICE_SERVICE_UUID.to_owned(),
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
|
||||||
let blocklist_test_service = create_service(&connectable_device, BLOCKLIST_TEST_SERVICE_UUID.to_owned())?;
|
let blocklist_test_service =
|
||||||
|
create_service(&connectable_device, BLOCKLIST_TEST_SERVICE_UUID.to_owned())?;
|
||||||
|
|
||||||
let blocklist_exclude_reads_characteristic =
|
let blocklist_exclude_reads_characteristic = create_characteristic(
|
||||||
create_characteristic(&blocklist_test_service,
|
&blocklist_test_service,
|
||||||
BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID.to_owned())?;
|
BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID.to_owned(),
|
||||||
|
)?;
|
||||||
blocklist_exclude_reads_characteristic
|
blocklist_exclude_reads_characteristic
|
||||||
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
|
||||||
|
|
||||||
let _blocklist_exclude_reads_descriptor =
|
let _blocklist_exclude_reads_descriptor = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&blocklist_exclude_reads_characteristic,
|
&blocklist_exclude_reads_characteristic,
|
||||||
BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID.to_owned(),
|
BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID.to_owned(),
|
||||||
vec![54; 3])?;
|
vec![54; 3],
|
||||||
|
)?;
|
||||||
|
|
||||||
let _blocklist_descriptor =
|
let _blocklist_descriptor = create_descriptor_with_value(
|
||||||
create_descriptor_with_value(&blocklist_exclude_reads_characteristic,
|
&blocklist_exclude_reads_characteristic,
|
||||||
BLOCKLIST_DESCRIPTOR_UUID.to_owned(),
|
BLOCKLIST_DESCRIPTOR_UUID.to_owned(),
|
||||||
vec![54; 3])?;
|
vec![54; 3],
|
||||||
|
)?;
|
||||||
|
|
||||||
let device_information_service = create_service(&connectable_device, DEVICE_INFORMATION_UUID.to_owned())?;
|
let device_information_service =
|
||||||
|
create_service(&connectable_device, DEVICE_INFORMATION_UUID.to_owned())?;
|
||||||
|
|
||||||
let _serial_number_string_characteristic =
|
let _serial_number_string_characteristic = create_characteristic(
|
||||||
create_characteristic(&device_information_service, SERIAL_NUMBER_STRING_UUID.to_owned())?;
|
&device_information_service,
|
||||||
|
SERIAL_NUMBER_STRING_UUID.to_owned(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let _generic_access_service = create_generic_access_service(&connectable_device, false)?;
|
let _generic_access_service = create_generic_access_service(&connectable_device, false)?;
|
||||||
|
|
||||||
let _heart_rate_service = create_heart_rate_service(&connectable_device, false)?;
|
let _heart_rate_service = create_heart_rate_service(&connectable_device, false)?;
|
||||||
|
|
||||||
let _human_interface_device_service =
|
let _human_interface_device_service = create_service(
|
||||||
create_service(&connectable_device, HUMAN_INTERFACE_DEVICE_SERVICE_UUID.to_owned())?;
|
&connectable_device,
|
||||||
|
HUMAN_INTERFACE_DEVICE_SERVICE_UUID.to_owned(),
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_glucose_heart_rate_devices(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
fn create_glucose_heart_rate_devices(adapter: &BluetoothAdapter) -> Result<(), Box<Error>> {
|
||||||
let glucose_devie = create_device_with_uuids(adapter,
|
let glucose_devie = create_device_with_uuids(
|
||||||
GLUCOSE_DEVICE_NAME.to_owned(),
|
adapter,
|
||||||
GLUCOSE_DEVICE_ADDRESS.to_owned(),
|
GLUCOSE_DEVICE_NAME.to_owned(),
|
||||||
vec![GLUCOSE_SERVICE_UUID.to_owned(),
|
GLUCOSE_DEVICE_ADDRESS.to_owned(),
|
||||||
TX_POWER_SERVICE_UUID.to_owned()])?;
|
vec![
|
||||||
|
GLUCOSE_SERVICE_UUID.to_owned(),
|
||||||
|
TX_POWER_SERVICE_UUID.to_owned(),
|
||||||
|
],
|
||||||
|
)?;
|
||||||
|
|
||||||
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
let heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
||||||
|
|
||||||
|
@ -470,9 +538,11 @@ pub fn test(manager: &mut BluetoothManager, data_set_name: String) -> Result<(),
|
||||||
UNICODE_DEVICE_ADAPTER => {
|
UNICODE_DEVICE_ADAPTER => {
|
||||||
set_adapter(adapter, UNICODE_DEVICE_ADAPTER.to_owned())?;
|
set_adapter(adapter, UNICODE_DEVICE_ADAPTER.to_owned())?;
|
||||||
|
|
||||||
let _unicode_device = create_device(adapter,
|
let _unicode_device = create_device(
|
||||||
UNICODE_DEVICE_NAME.to_owned(),
|
adapter,
|
||||||
UNICODE_DEVICE_ADDRESS.to_owned())?;
|
UNICODE_DEVICE_NAME.to_owned(),
|
||||||
|
UNICODE_DEVICE_ADDRESS.to_owned(),
|
||||||
|
)?;
|
||||||
},
|
},
|
||||||
MISSING_SERVICE_HEART_RATE_ADAPTER => {
|
MISSING_SERVICE_HEART_RATE_ADAPTER => {
|
||||||
set_adapter(adapter, MISSING_SERVICE_HEART_RATE_ADAPTER.to_owned())?;
|
set_adapter(adapter, MISSING_SERVICE_HEART_RATE_ADAPTER.to_owned())?;
|
||||||
|
@ -480,7 +550,10 @@ pub fn test(manager: &mut BluetoothManager, data_set_name: String) -> Result<(),
|
||||||
let _heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
let _heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
|
||||||
},
|
},
|
||||||
MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER => {
|
MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER => {
|
||||||
set_adapter(adapter, MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER.to_owned())?;
|
set_adapter(
|
||||||
|
adapter,
|
||||||
|
MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER.to_owned(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let _ = create_missing_characterisitc_heart_rate_device(adapter)?;
|
let _ = create_missing_characterisitc_heart_rate_device(adapter)?;
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,24 +10,17 @@ use std::string::String;
|
||||||
|
|
||||||
const EXCLUDE_READS: &'static str = "exclude-reads";
|
const EXCLUDE_READS: &'static str = "exclude-reads";
|
||||||
const EXCLUDE_WRITES: &'static str = "exclude-writes";
|
const EXCLUDE_WRITES: &'static str = "exclude-writes";
|
||||||
const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
const VALID_UUID_REGEX: &'static str =
|
||||||
|
"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||||
|
|
||||||
thread_local!(pub static BLUETOOTH_BLOCKLIST: RefCell<BluetoothBlocklist> =
|
thread_local!(pub static BLUETOOTH_BLOCKLIST: RefCell<BluetoothBlocklist> =
|
||||||
RefCell::new(BluetoothBlocklist(parse_blocklist())));
|
RefCell::new(BluetoothBlocklist(parse_blocklist())));
|
||||||
|
|
||||||
pub fn uuid_is_blocklisted(uuid: &str, exclude_type: Blocklist) -> bool {
|
pub fn uuid_is_blocklisted(uuid: &str, exclude_type: Blocklist) -> bool {
|
||||||
BLUETOOTH_BLOCKLIST.with(|blist| {
|
BLUETOOTH_BLOCKLIST.with(|blist| match exclude_type {
|
||||||
match exclude_type {
|
Blocklist::All => blist.borrow().is_blocklisted(uuid),
|
||||||
Blocklist::All => {
|
Blocklist::Reads => blist.borrow().is_blocklisted_for_reads(uuid),
|
||||||
blist.borrow().is_blocklisted(uuid)
|
Blocklist::Writes => blist.borrow().is_blocklisted_for_writes(uuid),
|
||||||
},
|
|
||||||
Blocklist::Reads => {
|
|
||||||
blist.borrow().is_blocklisted_for_reads(uuid)
|
|
||||||
}
|
|
||||||
Blocklist::Writes => {
|
|
||||||
blist.borrow().is_blocklisted_for_writes(uuid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,8 +45,9 @@ impl BluetoothBlocklist {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#blocklisted-for-reads
|
// https://webbluetoothcg.github.io/web-bluetooth/#blocklisted-for-reads
|
||||||
pub fn is_blocklisted_for_reads(&self, uuid: &str) -> bool {
|
pub fn is_blocklisted_for_reads(&self, uuid: &str) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Some(ref map) => map.get(uuid).map_or(false, |et| et.eq(&Blocklist::All) ||
|
Some(ref map) => map.get(uuid).map_or(false, |et| {
|
||||||
et.eq(&Blocklist::Reads)),
|
et.eq(&Blocklist::All) || et.eq(&Blocklist::Reads)
|
||||||
|
}),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +55,9 @@ impl BluetoothBlocklist {
|
||||||
// https://webbluetoothcg.github.io/web-bluetooth/#blocklisted-for-writes
|
// https://webbluetoothcg.github.io/web-bluetooth/#blocklisted-for-writes
|
||||||
pub fn is_blocklisted_for_writes(&self, uuid: &str) -> bool {
|
pub fn is_blocklisted_for_writes(&self, uuid: &str) -> bool {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Some(ref map) => map.get(uuid).map_or(false, |et| et.eq(&Blocklist::All) ||
|
Some(ref map) => map.get(uuid).map_or(false, |et| {
|
||||||
et.eq(&Blocklist::Writes)),
|
et.eq(&Blocklist::All) || et.eq(&Blocklist::Writes)
|
||||||
|
}),
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +93,7 @@ fn parse_blocklist() -> Option<HashMap<String, Blocklist>> {
|
||||||
exclude_type = Blocklist::Reads;
|
exclude_type = Blocklist::Reads;
|
||||||
},
|
},
|
||||||
Some(EXCLUDE_WRITES) => {
|
Some(EXCLUDE_WRITES) => {
|
||||||
exclude_type = Blocklist::Writes;
|
exclude_type = Blocklist::Writes;
|
||||||
},
|
},
|
||||||
// Step 4.4
|
// Step 4.4
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -5,7 +5,8 @@
|
||||||
extern crate embedder_traits;
|
extern crate embedder_traits;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
extern crate regex;
|
extern crate regex;
|
||||||
#[macro_use] extern crate serde;
|
#[macro_use]
|
||||||
|
extern crate serde;
|
||||||
|
|
||||||
pub mod blocklist;
|
pub mod blocklist;
|
||||||
pub mod scanfilter;
|
pub mod scanfilter;
|
||||||
|
@ -83,7 +84,13 @@ pub enum BluetoothRequest {
|
||||||
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResponseResult>),
|
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResponseResult>),
|
||||||
GATTServerConnect(String, IpcSender<BluetoothResponseResult>),
|
GATTServerConnect(String, IpcSender<BluetoothResponseResult>),
|
||||||
GATTServerDisconnect(String, IpcSender<BluetoothResult<()>>),
|
GATTServerDisconnect(String, IpcSender<BluetoothResult<()>>),
|
||||||
GetGATTChildren(String, Option<String>, bool, GATTType, IpcSender<BluetoothResponseResult>),
|
GetGATTChildren(
|
||||||
|
String,
|
||||||
|
Option<String>,
|
||||||
|
bool,
|
||||||
|
GATTType,
|
||||||
|
IpcSender<BluetoothResponseResult>,
|
||||||
|
),
|
||||||
ReadValue(String, IpcSender<BluetoothResponseResult>),
|
ReadValue(String, IpcSender<BluetoothResponseResult>),
|
||||||
WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
|
WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
|
||||||
EnableNotification(String, bool, IpcSender<BluetoothResponseResult>),
|
EnableNotification(String, bool, IpcSender<BluetoothResponseResult>),
|
||||||
|
@ -91,7 +98,11 @@ pub enum BluetoothRequest {
|
||||||
SetRepresentedToNull(Vec<String>, Vec<String>, Vec<String>),
|
SetRepresentedToNull(Vec<String>, Vec<String>, Vec<String>),
|
||||||
IsRepresentedDeviceNull(String, IpcSender<bool>),
|
IsRepresentedDeviceNull(String, IpcSender<bool>),
|
||||||
GetAvailability(IpcSender<BluetoothResponseResult>),
|
GetAvailability(IpcSender<BluetoothResponseResult>),
|
||||||
MatchesFilter(String, BluetoothScanfilterSequence, IpcSender<BluetoothResult<bool>>),
|
MatchesFilter(
|
||||||
|
String,
|
||||||
|
BluetoothScanfilterSequence,
|
||||||
|
IpcSender<BluetoothResult<bool>>,
|
||||||
|
),
|
||||||
Test(String, IpcSender<BluetoothResult<()>>),
|
Test(String, IpcSender<BluetoothResult<()>>),
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,13 @@ pub struct BluetoothScanfilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BluetoothScanfilter {
|
impl BluetoothScanfilter {
|
||||||
pub fn new(name: Option<String>,
|
pub fn new(
|
||||||
name_prefix: String,
|
name: Option<String>,
|
||||||
services: Vec<String>,
|
name_prefix: String,
|
||||||
manufacturer_data: Option<ManufacturerData>,
|
services: Vec<String>,
|
||||||
service_data: Option<ServiceData>)
|
manufacturer_data: Option<ManufacturerData>,
|
||||||
-> BluetoothScanfilter {
|
service_data: Option<ServiceData>,
|
||||||
|
) -> BluetoothScanfilter {
|
||||||
BluetoothScanfilter {
|
BluetoothScanfilter {
|
||||||
name: name,
|
name: name,
|
||||||
name_prefix: name_prefix,
|
name_prefix: name_prefix,
|
||||||
|
@ -73,12 +74,12 @@ impl BluetoothScanfilter {
|
||||||
|
|
||||||
pub fn is_empty_or_invalid(&self) -> bool {
|
pub fn is_empty_or_invalid(&self) -> bool {
|
||||||
(self.name.is_none() &&
|
(self.name.is_none() &&
|
||||||
self.name_prefix.is_empty() &&
|
self.name_prefix.is_empty() &&
|
||||||
self.get_services().is_empty() &&
|
self.get_services().is_empty() &&
|
||||||
self.manufacturer_data.is_none() &&
|
self.manufacturer_data.is_none() &&
|
||||||
self.service_data.is_none()) ||
|
self.service_data.is_none()) ||
|
||||||
self.get_name().unwrap_or("").len() > MAX_NAME_LENGTH ||
|
self.get_name().unwrap_or("").len() > MAX_NAME_LENGTH ||
|
||||||
self.name_prefix.len() > MAX_NAME_LENGTH
|
self.name_prefix.len() > MAX_NAME_LENGTH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +100,9 @@ impl BluetoothScanfilterSequence {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_services_set(&self) -> HashSet<String> {
|
fn get_services_set(&self) -> HashSet<String> {
|
||||||
self.iter().flat_map(|filter| filter.services.get_services_set()).collect()
|
self.iter()
|
||||||
|
.flat_map(|filter| filter.services.get_services_set())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_empty(&self) -> bool {
|
fn is_empty(&self) -> bool {
|
||||||
|
@ -114,9 +117,10 @@ pub struct RequestDeviceoptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestDeviceoptions {
|
impl RequestDeviceoptions {
|
||||||
pub fn new(filters: BluetoothScanfilterSequence,
|
pub fn new(
|
||||||
services: ServiceUUIDSequence)
|
filters: BluetoothScanfilterSequence,
|
||||||
-> RequestDeviceoptions {
|
services: ServiceUUIDSequence,
|
||||||
|
) -> RequestDeviceoptions {
|
||||||
RequestDeviceoptions {
|
RequestDeviceoptions {
|
||||||
filters: filters,
|
filters: filters,
|
||||||
optional_services: services,
|
optional_services: services,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue