diff options
author | gogerald <gogerald@chromium.org> | 2016-02-08 16:17:47 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-02-09 00:19:33 +0000 |
commit | d0355bb1d526163aa8d518291df2fd3424925f00 (patch) | |
tree | 43e00d220b2470ff1e028cdc830958f51695f47c /device | |
parent | 73567ae67dedd2ee3c017f2cbd4551d3c15555bb (diff) | |
download | chromium_src-d0355bb1d526163aa8d518291df2fd3424925f00.zip chromium_src-d0355bb1d526163aa8d518291df2fd3424925f00.tar.gz chromium_src-d0355bb1d526163aa8d518291df2fd3424925f00.tar.bz2 |
Implement BluetoothLowEnergyWrapperFake for Bluetooth test fixture
This CL implements BluetoothLowEnergyWrapperFake to make it support BluetoothTest.DiscoverLowEnergyDevice, BluetoothTest.DiscoverLowEnergyDeviceTwice and BluetoothTest.DiscoverMultipleLowEnergyDevices tests.
BUG=579202
Review URL: https://codereview.chromium.org/1676073002
Cr-Commit-Position: refs/heads/master@{#374229}
Diffstat (limited to 'device')
-rw-r--r-- | device/bluetooth/bluetooth_adapter_unittest.cc | 12 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_low_energy_win.h | 4 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_low_energy_win_fake.cc | 202 | ||||
-rw-r--r-- | device/bluetooth/bluetooth_low_energy_win_fake.h | 82 | ||||
-rw-r--r-- | device/bluetooth/test/bluetooth_test.h | 2 | ||||
-rw-r--r-- | device/bluetooth/test/bluetooth_test_win.cc | 55 | ||||
-rw-r--r-- | device/bluetooth/test/bluetooth_test_win.h | 2 |
7 files changed, 344 insertions, 15 deletions
diff --git a/device/bluetooth/bluetooth_adapter_unittest.cc b/device/bluetooth/bluetooth_adapter_unittest.cc index 45a5271..91bd19a 100644 --- a/device/bluetooth/bluetooth_adapter_unittest.cc +++ b/device/bluetooth/bluetooth_adapter_unittest.cc @@ -538,7 +538,7 @@ TEST_F(BluetoothTest, NoPermissions) { } #endif // defined(OS_ANDROID) || defined(OS_MACOSX) -#if defined(OS_ANDROID) || defined(OS_MACOSX) +#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) // Discovers a device. TEST_F(BluetoothTest, DiscoverLowEnergyDevice) { if (!PlatformSupportsLowEnergy()) { @@ -555,9 +555,9 @@ TEST_F(BluetoothTest, DiscoverLowEnergyDevice) { BluetoothDevice* device = adapter_->GetDevice(observer.last_device_address()); EXPECT_TRUE(device); } -#endif // defined(OS_ANDROID) || defined(OS_MACOSX) +#endif // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) -#if defined(OS_ANDROID) || defined(OS_MACOSX) +#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) // Discovers the same device multiple times. TEST_F(BluetoothTest, DiscoverLowEnergyDeviceTwice) { if (!PlatformSupportsLowEnergy()) { @@ -581,7 +581,7 @@ TEST_F(BluetoothTest, DiscoverLowEnergyDeviceTwice) { EXPECT_EQ(0, observer.device_added_count()); EXPECT_EQ(1u, adapter_->GetDevices().size()); } -#endif // defined(OS_ANDROID) || defined(OS_MACOSX) +#endif // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) #if defined(OS_ANDROID) || defined(OS_MACOSX) // Discovers a device, and then again with new Service UUIDs. @@ -634,7 +634,7 @@ TEST_F(BluetoothTest, DiscoverLowEnergyDeviceWithUpdatedUUIDs) { } #endif // defined(OS_ANDROID) || defined(OS_MACOSX) -#if defined(OS_ANDROID) || defined(OS_MACOSX) +#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) // Discovers multiple devices when addresses vary. TEST_F(BluetoothTest, DiscoverMultipleLowEnergyDevices) { if (!PlatformSupportsLowEnergy()) { @@ -651,7 +651,7 @@ TEST_F(BluetoothTest, DiscoverMultipleLowEnergyDevices) { EXPECT_EQ(2, observer.device_added_count()); EXPECT_EQ(2u, adapter_->GetDevices().size()); } -#endif // defined(OS_ANDROID) || defined(OS_MACOSX) +#endif // defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN) #if defined(OS_ANDROID) TEST_F(BluetoothTest, TogglePowerFakeAdapter) { diff --git a/device/bluetooth/bluetooth_low_energy_win.h b/device/bluetooth/bluetooth_low_energy_win.h index 9abdf34..9d92435 100644 --- a/device/bluetooth/bluetooth_low_energy_win.h +++ b/device/bluetooth/bluetooth_low_energy_win.h @@ -77,7 +77,7 @@ class DEVICE_BLUETOOTH_EXPORT DevicePropertyValue { // Returns true only on Windows platforms supporting Bluetooth Low Energy. bool DEVICE_BLUETOOTH_EXPORT IsBluetoothLowEnergySupported(); -struct BluetoothLowEnergyServiceInfo { +struct DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyServiceInfo { BluetoothLowEnergyServiceInfo(); ~BluetoothLowEnergyServiceInfo(); @@ -86,7 +86,7 @@ struct BluetoothLowEnergyServiceInfo { USHORT attribute_handle = 0; }; -struct BluetoothLowEnergyDeviceInfo { +struct DEVICE_BLUETOOTH_EXPORT BluetoothLowEnergyDeviceInfo { BluetoothLowEnergyDeviceInfo(); ~BluetoothLowEnergyDeviceInfo(); diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.cc b/device/bluetooth/bluetooth_low_energy_win_fake.cc index d1ef1df..60926be 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.cc +++ b/device/bluetooth/bluetooth_low_energy_win_fake.cc @@ -4,6 +4,13 @@ #include "device/bluetooth/bluetooth_low_energy_win_fake.h" +#include "base/strings/stringprintf.h" + +namespace { +const char kPlatformNotSupported[] = + "Bluetooth Low energy is only supported on Windows 8 and later."; +} // namespace + namespace device { namespace win { @@ -13,24 +20,207 @@ BluetoothLowEnergyWrapperFake::~BluetoothLowEnergyWrapperFake() {} bool BluetoothLowEnergyWrapperFake::EnumerateKnownBluetoothLowEnergyDevices( ScopedVector<BluetoothLowEnergyDeviceInfo>* devices, std::string* error) { - NOTIMPLEMENTED(); - return false; + if (!IsBluetoothLowEnergySupported()) { + *error = kPlatformNotSupported; + return false; + } + + for (auto& device : simulated_devices_) { + BluetoothLowEnergyDeviceInfo* device_info = + new BluetoothLowEnergyDeviceInfo(); + *device_info = *(device.second->device_info); + devices->push_back(device_info); + } + return true; } bool BluetoothLowEnergyWrapperFake:: EnumerateKnownBluetoothLowEnergyGattServiceDevices( ScopedVector<BluetoothLowEnergyDeviceInfo>* devices, std::string* error) { - NOTIMPLEMENTED(); - return false; + if (!IsBluetoothLowEnergySupported()) { + *error = kPlatformNotSupported; + return false; + } + + for (auto& device : simulated_devices_) { + for (auto& service : device.second->primary_services) { + BluetoothLowEnergyDeviceInfo* device_info = + new BluetoothLowEnergyDeviceInfo(); + *device_info = *(device.second->device_info); + base::string16 path = GenerateBLEGattServiceDevicePath( + device.second->device_info->path.value(), + service.second->service_info->AttributeHandle); + device_info->path = base::FilePath(path); + devices->push_back(device_info); + } + } + return true; } bool BluetoothLowEnergyWrapperFake::EnumerateKnownBluetoothLowEnergyServices( const base::FilePath& device_path, ScopedVector<BluetoothLowEnergyServiceInfo>* services, std::string* error) { - NOTIMPLEMENTED(); - return false; + if (!IsBluetoothLowEnergySupported()) { + *error = kPlatformNotSupported; + return false; + } + + base::string16 device_address = + ExtractDeviceAddressFromDevicePath(device_path.value()); + base::string16 service_attribute_handle = + ExtractServiceAttributeHandleFromDevicePath(device_path.value()); + + BLEDevicesMap::iterator it_d = simulated_devices_.find( + std::string(device_address.begin(), device_address.end())); + CHECK(it_d != simulated_devices_.end()); + + // |service_attribute_handle| is empty means |device_path| is a BLE device + // path, otherwise it is a BLE GATT service device path. + if (service_attribute_handle.empty()) { + // Return all primary services for BLE device. + for (auto& primary_service : it_d->second->primary_services) { + BluetoothLowEnergyServiceInfo* service_info = + new BluetoothLowEnergyServiceInfo(); + service_info->uuid = primary_service.second->service_info->ServiceUuid; + service_info->attribute_handle = + primary_service.second->service_info->AttributeHandle; + services->push_back(service_info); + } + } else { + // Return corresponding GATT service for BLE GATT service device. + BLEGattServicesMap::iterator it_s = + it_d->second->primary_services.find(std::string( + service_attribute_handle.begin(), service_attribute_handle.end())); + CHECK(it_s != it_d->second->primary_services.end()); + BluetoothLowEnergyServiceInfo* service_info = + new BluetoothLowEnergyServiceInfo(); + service_info->uuid = it_s->second->service_info->ServiceUuid; + service_info->attribute_handle = + it_s->second->service_info->AttributeHandle; + services->push_back(service_info); + } + + return true; +} + +BLEDevice* BluetoothLowEnergyWrapperFake::SimulateBLEDevice( + std::string device_name, + BLUETOOTH_ADDRESS device_address) { + BLEDevice* device = new BLEDevice(); + BluetoothLowEnergyDeviceInfo* device_info = + new BluetoothLowEnergyDeviceInfo(); + std::string string_device_address = + BluetoothAddressToCanonicalString(device_address); + device_info->path = + base::FilePath(GenerateBLEDevicePath(string_device_address)); + device_info->friendly_name = device_name; + device_info->address = device_address; + device->device_info.reset(device_info); + simulated_devices_[string_device_address] = make_scoped_ptr(device); + return device; +} + +BLEGattService* BluetoothLowEnergyWrapperFake::SimulateBLEGattService( + BLEDevice* device, + std::string uuid) { + CHECK(device); + + BLEGattService* service = new BLEGattService(); + PBTH_LE_GATT_SERVICE service_info = new BTH_LE_GATT_SERVICE[1]; + std::string string_device_address = + BluetoothAddressToCanonicalString(device->device_info->address); + service_info->AttributeHandle = + GenerateAUniqueAttributeHandle(string_device_address); + service_info->ServiceUuid = CanonicalStringToBTH_LE_UUID(uuid); + service->service_info.reset(service_info); + device->primary_services[std::to_string(service_info->AttributeHandle)] = + make_scoped_ptr(service); + return service; +} + +USHORT BluetoothLowEnergyWrapperFake::GenerateAUniqueAttributeHandle( + std::string device_address) { + scoped_ptr<std::set<USHORT>>& set_of_ushort = + attribute_handle_table_[device_address]; + if (set_of_ushort) { + USHORT max_attribute_handle = *set_of_ushort->rbegin(); + if (max_attribute_handle < 0xFFFF) { + USHORT new_attribute_handle = max_attribute_handle + 1; + set_of_ushort->insert(new_attribute_handle); + return new_attribute_handle; + } else { + USHORT i = 1; + for (; i < 0xFFFF; i++) { + if (set_of_ushort->find(i) == set_of_ushort->end()) + break; + } + if (i >= 0xFFFF) + return 0; + set_of_ushort->insert(i); + return i; + } + } + + USHORT smallest_att_handle = 1; + std::set<USHORT>* new_set = new std::set<USHORT>(); + new_set->insert(smallest_att_handle); + set_of_ushort.reset(new_set); + return smallest_att_handle; +} + +base::string16 BluetoothLowEnergyWrapperFake::GenerateBLEDevicePath( + std::string device_address) { + return base::string16(device_address.begin(), device_address.end()); +} + +base::string16 BluetoothLowEnergyWrapperFake::GenerateBLEGattServiceDevicePath( + base::string16 resident_device_path, + USHORT service_attribute_handle) { + std::string sub_path = std::to_string(service_attribute_handle); + return resident_device_path + L"/" + + base::string16(sub_path.begin(), sub_path.end()); +} + +base::string16 +BluetoothLowEnergyWrapperFake::ExtractDeviceAddressFromDevicePath( + base::string16 path) { + std::size_t found = path.find('/'); + if (found != base::string16::npos) { + return path.substr(0, found - 1); + } + return path; +} + +base::string16 +BluetoothLowEnergyWrapperFake::ExtractServiceAttributeHandleFromDevicePath( + base::string16 path) { + std::size_t found = path.find('/'); + if (found == base::string16::npos) + return base::string16(); + return path.substr(found + 1); +} + +BTH_LE_UUID BluetoothLowEnergyWrapperFake::CanonicalStringToBTH_LE_UUID( + std::string uuid) { + BTH_LE_UUID win_uuid; + // Only short UUIDs (4 hex digits) have beened used in BluetoothTest right + // now. Need fix after using long UUIDs. + win_uuid.IsShortUuid = true; + unsigned int data[1]; + int result = sscanf_s(uuid.c_str(), "%04x", &data[0]); + CHECK(result == 1); + win_uuid.Value.ShortUuid = data[0]; + return win_uuid; +} + +std::string BluetoothLowEnergyWrapperFake::BluetoothAddressToCanonicalString( + const BLUETOOTH_ADDRESS& btha) { + std::string result = base::StringPrintf( + "%02X:%02X:%02X:%02X:%02X:%02X", btha.rgBytes[5], btha.rgBytes[4], + btha.rgBytes[3], btha.rgBytes[2], btha.rgBytes[1], btha.rgBytes[0]); + return result; } } // namespace win diff --git a/device/bluetooth/bluetooth_low_energy_win_fake.h b/device/bluetooth/bluetooth_low_energy_win_fake.h index a22d5cb..e93774f 100644 --- a/device/bluetooth/bluetooth_low_energy_win_fake.h +++ b/device/bluetooth/bluetooth_low_energy_win_fake.h @@ -7,9 +7,53 @@ #include "device/bluetooth/bluetooth_low_energy_win.h" +#include <set> +#include <unordered_map> + namespace device { namespace win { +struct BLEDevice; +struct BLEGattService; +struct BLEGattCharacteristic; +struct BLEGattDescriptor; + +// The key of BLEDevicesMap is the string of the BLE device address. +typedef std::unordered_map<std::string, scoped_ptr<BLEDevice>> BLEDevicesMap; +// The key of BLEGattServicesMap, BLEGattCharacteristicsMap and +// BLEGattDescriptorsMap is the string of the attribute handle. +typedef std::unordered_map<std::string, scoped_ptr<BLEGattService>> + BLEGattServicesMap; +typedef std::unordered_map<std::string, scoped_ptr<BLEGattCharacteristic>> + BLEGattCharacteristicsMap; +typedef std::unordered_map<std::string, scoped_ptr<BLEGattDescriptor>> + BLEGattDescriptorsMap; +// The key of BLEAttributeHandleTable is the string of the BLE device address. +typedef std::unordered_map<std::string, scoped_ptr<std::set<USHORT>>> + BLEAttributeHandleTable; + +struct BLEDevice { + scoped_ptr<BluetoothLowEnergyDeviceInfo> device_info; + BLEGattServicesMap primary_services; +}; + +struct BLEGattService { + scoped_ptr<BTH_LE_GATT_SERVICE> service_info; + BLEGattServicesMap included_services; + BLEGattCharacteristicsMap included_characteristics; +}; + +struct BLEGattCharacteristic { + scoped_ptr<BTH_LE_GATT_CHARACTERISTIC> characteristic_info; + scoped_ptr<BTH_LE_GATT_CHARACTERISTIC_VALUE> value; + BLEGattDescriptorsMap included_descriptors; +}; + +struct BLEGattDescriptor { + scoped_ptr<BTH_LE_GATT_DESCRIPTOR> descriptor_info; + scoped_ptr<BTH_LE_GATT_DESCRIPTOR_VALUE> value; +}; + // Fake implementation of BluetoothLowEnergyWrapper. Used for BluetoothTestWin. class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { public: @@ -26,6 +70,44 @@ class BluetoothLowEnergyWrapperFake : public BluetoothLowEnergyWrapper { const base::FilePath& device_path, ScopedVector<BluetoothLowEnergyServiceInfo>* services, std::string* error) override; + + BLEDevice* SimulateBLEDevice(std::string device_name, + BLUETOOTH_ADDRESS device_address); + BLEGattService* SimulateBLEGattService(BLEDevice* device, std::string uuid); + + private: + // Generate an unique attribute handle on |device_address|. + USHORT GenerateAUniqueAttributeHandle(std::string device_address); + + // Generate device path for the BLE device with |device_address|. + base::string16 GenerateBLEDevicePath(std::string device_address); + + // Generate GATT service device path of the service with + // |service_attribute_handle|. |resident_device_path| is the BLE device this + // GATT service belongs to. + base::string16 GenerateBLEGattServiceDevicePath( + base::string16 resident_device_path, + USHORT service_attribute_handle); + + // Extract device address from the device |path| generated by + // GenerateBLEDevicePath or GenerateBLEGattServiceDevicePath. + base::string16 ExtractDeviceAddressFromDevicePath(base::string16 path); + + // Extract service attribute handle from the |path| generated by + // GenerateBLEGattServiceDevicePath. + base::string16 ExtractServiceAttributeHandleFromDevicePath( + base::string16 path); + + // The canonical BLE device address string format is the + // BluetoothDevice::CanonicalizeAddress. + std::string BluetoothAddressToCanonicalString(const BLUETOOTH_ADDRESS& btha); + + // The canonical UUID string format is device::BluetoothUUID.value(). + BTH_LE_UUID CanonicalStringToBTH_LE_UUID(std::string uuid); + + // Table to store allocated attribute handle for a device. + BLEAttributeHandleTable attribute_handle_table_; + BLEDevicesMap simulated_devices_; }; } // namespace win diff --git a/device/bluetooth/test/bluetooth_test.h b/device/bluetooth/test/bluetooth_test.h index 7191345..5e34d90 100644 --- a/device/bluetooth/test/bluetooth_test.h +++ b/device/bluetooth/test/bluetooth_test.h @@ -58,7 +58,7 @@ class BluetoothTestBase : public testing::Test { // Calls adapter_->StartDiscoverySessionWithFilter with Low Energy transport, // and this fixture's callbacks expecting success. // Then RunLoop().RunUntilIdle(). - void StartLowEnergyDiscoverySession(); + virtual void StartLowEnergyDiscoverySession(); // Calls adapter_->StartDiscoverySessionWithFilter with Low Energy transport, // and this fixture's callbacks expecting error. diff --git a/device/bluetooth/test/bluetooth_test_win.cc b/device/bluetooth/test/bluetooth_test_win.cc index 4e6536f..2bbaeee 100644 --- a/device/bluetooth/test/bluetooth_test_win.cc +++ b/device/bluetooth/test/bluetooth_test_win.cc @@ -73,4 +73,59 @@ void BluetoothTestWin::InitWithFakeAdapter() { bool BluetoothTestWin::DenyPermission() { return false; } + +void BluetoothTestWin::StartLowEnergyDiscoverySession() { + __super ::StartLowEnergyDiscoverySession(); + bluetooth_task_runner_->RunPendingTasks(); + ui_task_runner_->RunPendingTasks(); +} + +BluetoothDevice* BluetoothTestWin::DiscoverLowEnergyDevice(int device_ordinal) { + if (device_ordinal > 4 || device_ordinal < 1) + return nullptr; + + std::string device_name = kTestDeviceName; + std::string device_address = kTestDeviceAddress1; + std::string service_uuid_1; + std::string service_uuid_2; + + switch (device_ordinal) { + case 1: { + service_uuid_1 = kTestUUIDGenericAccess; + service_uuid_2 = kTestUUIDGenericAttribute; + } break; + case 2: { + service_uuid_1 = kTestUUIDImmediateAlert; + service_uuid_2 = kTestUUIDLinkLoss; + } break; + case 3: { + device_name = kTestDeviceNameEmpty; + } break; + case 4: { + device_name = kTestDeviceNameEmpty; + device_address = kTestDeviceAddress2; + } break; + } + + win::BLEDevice* simulated_device = fake_bt_le_wrapper_->SimulateBLEDevice( + device_name, CanonicalStringToBLUETOOTH_ADDRESS(device_address)); + if (simulated_device != nullptr) { + if (!service_uuid_1.empty()) + fake_bt_le_wrapper_->SimulateBLEGattService(simulated_device, + service_uuid_1); + if (!service_uuid_2.empty()) + fake_bt_le_wrapper_->SimulateBLEGattService(simulated_device, + service_uuid_2); + } + bluetooth_task_runner_->RunPendingTasks(); + ui_task_runner_->RunPendingTasks(); + + std::vector<BluetoothDevice*> devices = adapter_win_->GetDevices(); + for (auto device : devices) { + if (device->GetAddress() == device_address) + return device; + } + + return nullptr; +} } diff --git a/device/bluetooth/test/bluetooth_test_win.h b/device/bluetooth/test/bluetooth_test_win.h index 883a4fd..2fea2ac 100644 --- a/device/bluetooth/test/bluetooth_test_win.h +++ b/device/bluetooth/test/bluetooth_test_win.h @@ -28,6 +28,8 @@ class BluetoothTestWin : public BluetoothTestBase { void InitWithoutDefaultAdapter() override; void InitWithFakeAdapter() override; bool DenyPermission() override; + void StartLowEnergyDiscoverySession() override; + BluetoothDevice* DiscoverLowEnergyDevice(int device_ordinal) override; private: scoped_refptr<base::TestSimpleTaskRunner> ui_task_runner_; |