use std::borrow::ToOwned;
use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::error::Error;
use std::string::String;
use uuid::Uuid;
use crate::bluetooth::{
BluetoothAdapter, BluetoothDevice, BluetoothGATTCharacteristic, BluetoothGATTDescriptor,
BluetoothGATTService,
};
use crate::BluetoothManager;
thread_local!(pub static CACHED_IDS: RefCell<HashSet<Uuid>> = RefCell::new(HashSet::new()));
const ADAPTER_ERROR: &str = "No adapter found";
const WRONG_DATA_SET_ERROR: &str = "Wrong data set name was provided";
const READ_FLAG: &str = "read";
const WRITE_FLAG: &str = "write";
const NOTIFY_FLAG: &str = "notify";
const NOT_PRESENT_ADAPTER: &str = "NotPresentAdapter";
const NOT_POWERED_ADAPTER: &str = "NotPoweredAdapter";
const EMPTY_ADAPTER: &str = "EmptyAdapter";
const GLUCOSE_HEART_RATE_ADAPTER: &str = "GlucoseHeartRateAdapter";
const UNICODE_DEVICE_ADAPTER: &str = "UnicodeDeviceAdapter";
const MISSING_SERVICE_HEART_RATE_ADAPTER: &str = "MissingServiceHeartRateAdapter";
const MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER: &str = "MissingCharacteristicHeartRateAdapter";
const MISSING_DESCRIPTOR_HEART_RATE_ADAPTER: &str = "MissingDescriptorHeartRateAdapter";
const HEART_RATE_ADAPTER: &str = "HeartRateAdapter";
const EMPTY_NAME_HEART_RATE_ADAPTER: &str = "EmptyNameHeartRateAdapter";
const NO_NAME_HEART_RATE_ADAPTER: &str = "NoNameHeartRateAdapter";
const TWO_HEART_RATE_SERVICES_ADAPTER: &str = "TwoHeartRateServicesAdapter";
const BLOCKLIST_TEST_ADAPTER: &str = "BlocklistTestAdapter";
const CONNECTABLE_DEVICE_NAME: &str = "Connectable Device";
const EMPTY_DEVICE_NAME: &str = "";
const GLUCOSE_DEVICE_NAME: &str = "Glucose Device";
const HEART_RATE_DEVICE_NAME: &str = "Heart Rate Device";
const UNICODE_DEVICE_NAME: &str = "❤❤❤❤❤❤❤❤❤";
const CONNECTABLE_DEVICE_ADDRESS: &str = "00:00:00:00:00:04";
const GLUCOSE_DEVICE_ADDRESS: &str = "00:00:00:00:00:02";
const HEART_RATE_DEVICE_ADDRESS: &str = "00:00:00:00:00:03";
const UNICODE_DEVICE_ADDRESS: &str = "00:00:00:00:00:01";
const BLOCKLIST_TEST_SERVICE_UUID: &str = "611c954a-263b-4f4a-aab6-01ddb953f985";
const DEVICE_INFORMATION_UUID: &str = "0000180a-0000-1000-8000-00805f9b34fb";
const GENERIC_ACCESS_SERVICE_UUID: &str = "00001800-0000-1000-8000-00805f9b34fb";
const GLUCOSE_SERVICE_UUID: &str = "00001808-0000-1000-8000-00805f9b34fb";
const HEART_RATE_SERVICE_UUID: &str = "0000180d-0000-1000-8000-00805f9b34fb";
const HUMAN_INTERFACE_DEVICE_SERVICE_UUID: &str = "00001812-0000-1000-8000-00805f9b34fb";
const TX_POWER_SERVICE_UUID: &str = "00001804-0000-1000-8000-00805f9b34fb";
const BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID: &str = "bad1c9a2-9a5b-4015-8b60-1579bbbf2135";
const BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID: &str = "00002a38-0000-1000-8000-00805f9b34fb";
const DEVICE_NAME_CHARACTERISTIC_UUID: &str = "00002a00-0000-1000-8000-00805f9b34fb";
const HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID: &str = "00002a37-0000-1000-8000-00805f9b34fb";
const PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID: &str = "00002a02-0000-1000-8000-00805f9b34fb";
const SERIAL_NUMBER_STRING_UUID: &str = "00002a25-0000-1000-8000-00805f9b34fb";
const BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID: &str = "aaaaaaaa-aaaa-1181-0510-810819516110";
const BLOCKLIST_DESCRIPTOR_UUID: &str = "07711111-6104-0970-7011-1107105110aa";
const CHARACTERISTIC_USER_DESCRIPTION_UUID: &str = "00002901-0000-1000-8000-00805f9b34fb";
const CLIENT_CHARACTERISTIC_CONFIGURATION_UUID: &str = "00002902-0000-1000-8000-00805f9b34fb";
const NUMBER_OF_DIGITALS_UUID: &str = "00002909-0000-1000-8000-00805f9b34fb";
const HEART_RATE_DEVICE_NAME_DESCRIPTION: &str = "The name of this device.";
fn generate_id() -> Uuid {
let mut id = Uuid::nil();
let mut generated = false;
while !generated {
id = Uuid::new_v4();
CACHED_IDS.with(|cache| {
if !cache.borrow().contains(&id) {
cache.borrow_mut().insert(id);
generated = true;
}
});
}
id
}
fn set_adapter(adapter: &BluetoothAdapter, adapter_name: String) -> Result<(), Box<dyn Error>> {
adapter.set_name(adapter_name)?;
adapter.set_powered(true)?;
adapter.set_discoverable(true)?;
Ok(())
}
fn create_device(
adapter: &BluetoothAdapter,
name: String,
address: String,
) -> Result<BluetoothDevice, Box<dyn Error>> {
let device = adapter.create_mock_device(generate_id().to_string())?;
device.set_name(Some(name))?;
device.set_address(address)?;
device.set_connectable(true)?;
Ok(device)
}
fn create_device_with_uuids(
adapter: &BluetoothAdapter,
name: String,
address: String,
uuids: Vec<String>,
) -> Result<BluetoothDevice, Box<dyn Error>> {
let device = create_device(adapter, name, address)?;
device.set_uuids(uuids)?;
Ok(device)
}
fn create_service(
device: &BluetoothDevice,
uuid: String,
) -> Result<BluetoothGATTService, Box<dyn Error>> {
let service =
BluetoothGATTService::create_mock_service(device.clone(), generate_id().to_string())?;
service.set_uuid(uuid)?;
Ok(service)
}
fn create_characteristic(
service: &BluetoothGATTService,
uuid: String,
) -> Result<BluetoothGATTCharacteristic, Box<dyn Error>> {
let characteristic = BluetoothGATTCharacteristic::create_mock_characteristic(
service.clone(),
generate_id().to_string(),
)?;
characteristic.set_uuid(uuid)?;
Ok(characteristic)
}
fn create_characteristic_with_value(
service: &BluetoothGATTService,
uuid: String,
value: Vec<u8>,
) -> Result<BluetoothGATTCharacteristic, Box<dyn Error>> {
let characteristic = create_characteristic(service, uuid)?;
characteristic.set_value(value)?;
Ok(characteristic)
}
fn create_descriptor(
characteristic: &BluetoothGATTCharacteristic,
uuid: String,
) -> Result<BluetoothGATTDescriptor, Box<dyn Error>> {
let descriptor = BluetoothGATTDescriptor::create_mock_descriptor(
characteristic.clone(),
generate_id().to_string(),
)?;
descriptor.set_uuid(uuid)?;
Ok(descriptor)
}
fn create_descriptor_with_value(
characteristic: &BluetoothGATTCharacteristic,
uuid: String,
value: Vec<u8>,
) -> Result<BluetoothGATTDescriptor, Box<dyn Error>> {
let descriptor = create_descriptor(characteristic, uuid)?;
descriptor.set_value(value)?;
Ok(descriptor)
}
fn create_heart_rate_service(
device: &BluetoothDevice,
empty: bool,
) -> Result<BluetoothGATTService, Box<dyn Error>> {
let heart_rate_service = create_service(device, HEART_RATE_SERVICE_UUID.to_owned())?;
if empty {
return Ok(heart_rate_service);
}
let heart_rate_measurement_characteristic = create_characteristic_with_value(
&heart_rate_service,
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
vec![0],
)?;
heart_rate_measurement_characteristic.set_flags(vec![
NOTIFY_FLAG.to_string(),
READ_FLAG.to_string(),
WRITE_FLAG.to_string(),
])?;
let body_sensor_location_characteristic_1 = create_characteristic_with_value(
&heart_rate_service,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![49],
)?;
body_sensor_location_characteristic_1
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
let body_sensor_location_characteristic_2 = create_characteristic_with_value(
&heart_rate_service,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![50],
)?;
body_sensor_location_characteristic_2
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
Ok(heart_rate_service)
}
fn create_generic_access_service(
device: &BluetoothDevice,
empty: bool,
) -> Result<BluetoothGATTService, Box<dyn Error>> {
let generic_access_service = create_service(device, GENERIC_ACCESS_SERVICE_UUID.to_owned())?;
if empty {
return Ok(generic_access_service);
}
let device_name_characteristic = create_characteristic_with_value(
&generic_access_service,
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
HEART_RATE_DEVICE_NAME.as_bytes().to_vec(),
)?;
device_name_characteristic.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
let number_of_digitals_descriptor_1 = create_descriptor_with_value(
&device_name_characteristic,
NUMBER_OF_DIGITALS_UUID.to_owned(),
vec![49],
)?;
number_of_digitals_descriptor_1
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
let number_of_digitals_descriptor_2 = create_descriptor_with_value(
&device_name_characteristic,
NUMBER_OF_DIGITALS_UUID.to_owned(),
vec![50],
)?;
number_of_digitals_descriptor_2
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
let _characteristic_user_description = create_descriptor_with_value(
&device_name_characteristic,
CHARACTERISTIC_USER_DESCRIPTION_UUID.to_owned(),
HEART_RATE_DEVICE_NAME_DESCRIPTION.as_bytes().to_vec(),
)?;
let _client_characteristic_configuration = create_descriptor_with_value(
&device_name_characteristic,
CLIENT_CHARACTERISTIC_CONFIGURATION_UUID.to_owned(),
vec![0],
)?;
let peripheral_privacy_flag_characteristic = create_characteristic(
&generic_access_service,
PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned(),
)?;
peripheral_privacy_flag_characteristic
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
Ok(generic_access_service)
}
fn create_heart_rate_device(
adapter: &BluetoothAdapter,
empty: bool,
) -> Result<BluetoothDevice, Box<dyn Error>> {
let heart_rate_device = create_device_with_uuids(
adapter,
HEART_RATE_DEVICE_NAME.to_owned(),
HEART_RATE_DEVICE_ADDRESS.to_owned(),
vec![
GENERIC_ACCESS_SERVICE_UUID.to_owned(),
HEART_RATE_SERVICE_UUID.to_owned(),
],
)?;
if empty {
return Ok(heart_rate_device);
}
let _generic_access_service = create_generic_access_service(&heart_rate_device, false)?;
let _heart_rate_service = create_heart_rate_service(&heart_rate_device, false)?;
Ok(heart_rate_device)
}
fn create_missing_characterisitc_heart_rate_device(
adapter: &BluetoothAdapter,
) -> Result<(), Box<dyn Error>> {
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 _heart_rate_service_empty = create_heart_rate_service(&heart_rate_device_empty, true)?;
Ok(())
}
fn create_missing_descriptor_heart_rate_device(
adapter: &BluetoothAdapter,
) -> Result<(), Box<dyn Error>> {
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 _device_name_characteristic = create_characteristic_with_value(
&generic_access_service_empty,
DEVICE_NAME_CHARACTERISTIC_UUID.to_owned(),
HEART_RATE_DEVICE_NAME.as_bytes().to_vec(),
)?;
let peripheral_privacy_flag_characteristic = create_characteristic(
&generic_access_service_empty,
PERIPHERAL_PRIVACY_FLAG_CHARACTERISTIC_UUID.to_owned(),
)?;
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)?;
Ok(())
}
fn create_two_heart_rate_services_device(adapter: &BluetoothAdapter) -> Result<(), Box<dyn Error>> {
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_SERVICE_UUID.to_owned(),
HEART_RATE_SERVICE_UUID.to_owned(),
])?;
let _generic_access_service = create_generic_access_service(&heart_rate_device_empty, false)?;
let heart_rate_service_empty_1 = 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 = create_characteristic_with_value(
&heart_rate_service_empty_1,
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
vec![0],
)?;
heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()])?;
let _body_sensor_location_characteristic_1 = create_characteristic_with_value(
&heart_rate_service_empty_1,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![49],
)?;
let _body_sensor_location_characteristic_2 = create_characteristic_with_value(
&heart_rate_service_empty_2,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![50],
)?;
Ok(())
}
fn create_blocklisted_device(adapter: &BluetoothAdapter) -> Result<(), Box<dyn Error>> {
let connectable_device = create_device_with_uuids(
adapter,
CONNECTABLE_DEVICE_NAME.to_owned(),
CONNECTABLE_DEVICE_ADDRESS.to_owned(),
vec![
BLOCKLIST_TEST_SERVICE_UUID.to_owned(),
DEVICE_INFORMATION_UUID.to_owned(),
GENERIC_ACCESS_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_exclude_reads_characteristic = create_characteristic(
&blocklist_test_service,
BLOCKLIST_EXCLUDE_READS_CHARACTERISTIC_UUID.to_owned(),
)?;
blocklist_exclude_reads_characteristic
.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()])?;
let _blocklist_exclude_reads_descriptor = create_descriptor_with_value(
&blocklist_exclude_reads_characteristic,
BLOCKLIST_EXCLUDE_READS_DESCRIPTOR_UUID.to_owned(),
vec![54; 3],
)?;
let _blocklist_descriptor = create_descriptor_with_value(
&blocklist_exclude_reads_characteristic,
BLOCKLIST_DESCRIPTOR_UUID.to_owned(),
vec![54; 3],
)?;
let device_information_service =
create_service(&connectable_device, DEVICE_INFORMATION_UUID.to_owned())?;
let _serial_number_string_characteristic = create_characteristic(
&device_information_service,
SERIAL_NUMBER_STRING_UUID.to_owned(),
)?;
let _generic_access_service = create_generic_access_service(&connectable_device, false)?;
let _heart_rate_service = create_heart_rate_service(&connectable_device, false)?;
let _human_interface_device_service = create_service(
&connectable_device,
HUMAN_INTERFACE_DEVICE_SERVICE_UUID.to_owned(),
)?;
Ok(())
}
fn create_glucose_heart_rate_devices(adapter: &BluetoothAdapter) -> Result<(), Box<dyn Error>> {
let glucose_devie = create_device_with_uuids(
adapter,
GLUCOSE_DEVICE_NAME.to_owned(),
GLUCOSE_DEVICE_ADDRESS.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 mut manufacturer_dta = HashMap::new();
manufacturer_dta.insert(17, vec![1, 2, 3]);
glucose_devie.set_manufacturer_data(manufacturer_dta)?;
let mut service_data = HashMap::new();
service_data.insert(GLUCOSE_SERVICE_UUID.to_owned(), vec![1, 2, 3]);
glucose_devie.set_service_data(service_data)?;
service_data = HashMap::new();
service_data.insert(HEART_RATE_SERVICE_UUID.to_owned(), vec![1, 2, 3]);
heart_rate_device_empty.set_service_data(service_data)?;
Ok(())
}
pub fn test(manager: &mut BluetoothManager, data_set_name: String) -> Result<(), Box<dyn Error>> {
let may_existing_adapter = manager.get_or_create_adapter();
let adapter = match may_existing_adapter.as_ref() {
Some(adapter) => adapter,
None => return Err(Box::from(ADAPTER_ERROR.to_string())),
};
match data_set_name.as_str() {
NOT_PRESENT_ADAPTER => {
set_adapter(adapter, NOT_PRESENT_ADAPTER.to_owned())?;
adapter.set_present(false)?;
},
NOT_POWERED_ADAPTER => {
set_adapter(adapter, NOT_POWERED_ADAPTER.to_owned())?;
adapter.set_powered(false)?;
},
EMPTY_ADAPTER => {
set_adapter(adapter, EMPTY_ADAPTER.to_owned())?;
},
GLUCOSE_HEART_RATE_ADAPTER => {
set_adapter(adapter, GLUCOSE_HEART_RATE_ADAPTER.to_owned())?;
create_glucose_heart_rate_devices(adapter)?;
},
UNICODE_DEVICE_ADAPTER => {
set_adapter(adapter, UNICODE_DEVICE_ADAPTER.to_owned())?;
let _unicode_device = create_device(
adapter,
UNICODE_DEVICE_NAME.to_owned(),
UNICODE_DEVICE_ADDRESS.to_owned(),
)?;
},
MISSING_SERVICE_HEART_RATE_ADAPTER => {
set_adapter(adapter, MISSING_SERVICE_HEART_RATE_ADAPTER.to_owned())?;
let _heart_rate_device_empty = create_heart_rate_device(adapter, true)?;
},
MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER => {
set_adapter(
adapter,
MISSING_CHARACTERISTIC_HEART_RATE_ADAPTER.to_owned(),
)?;
create_missing_characterisitc_heart_rate_device(adapter)?;
},
MISSING_DESCRIPTOR_HEART_RATE_ADAPTER => {
set_adapter(adapter, MISSING_DESCRIPTOR_HEART_RATE_ADAPTER.to_owned())?;
create_missing_descriptor_heart_rate_device(adapter)?;
},
HEART_RATE_ADAPTER => {
set_adapter(adapter, HEART_RATE_ADAPTER.to_owned())?;
let _heart_rate_device = create_heart_rate_device(adapter, false)?;
},
EMPTY_NAME_HEART_RATE_ADAPTER => {
set_adapter(adapter, EMPTY_NAME_HEART_RATE_ADAPTER.to_owned())?;
let heart_rate_device = create_heart_rate_device(adapter, false)?;
heart_rate_device.set_name(Some(EMPTY_DEVICE_NAME.to_owned()))?;
},
NO_NAME_HEART_RATE_ADAPTER => {
set_adapter(adapter, NO_NAME_HEART_RATE_ADAPTER.to_owned())?;
let heart_rate_device = create_heart_rate_device(adapter, false)?;
heart_rate_device.set_name(None)?;
},
TWO_HEART_RATE_SERVICES_ADAPTER => {
set_adapter(adapter, TWO_HEART_RATE_SERVICES_ADAPTER.to_owned())?;
create_two_heart_rate_services_device(adapter)?;
},
BLOCKLIST_TEST_ADAPTER => {
set_adapter(adapter, BLOCKLIST_TEST_ADAPTER.to_owned())?;
create_blocklisted_device(adapter)?;
},
_ => return Err(Box::from(WRONG_DATA_SET_ERROR.to_string())),
}
Ok(())
}