| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "device/bluetooth/bluetooth_low_energy_win.h" | 5 #include "device/bluetooth/bluetooth_low_energy_win.h" |
| 6 | 6 |
| 7 #include <cfg.h> | 7 #include "base/files/file.h" |
| 8 #define INITGUID // For DEVPKEY_Xxxx guid/pid pairs | |
| 9 #include <devpkey.h> | |
| 10 | |
| 11 #include "base/logging.h" | 8 #include "base/logging.h" |
| 12 #include "base/strings/sys_string_conversions.h" | 9 #include "base/strings/sys_string_conversions.h" |
| 10 #include "base/win/scoped_handle.h" |
| 13 #include "base/win/windows_version.h" | 11 #include "base/win/windows_version.h" |
| 14 | 12 |
| 15 namespace { | 13 namespace { |
| 16 | 14 |
| 17 using device::win::DeviceRegistryPropertyValue; | 15 using device::win::DeviceRegistryPropertyValue; |
| 18 using device::win::DevicePropertyValue; | 16 using device::win::DevicePropertyValue; |
| 17 using device::win::BluetoothLowEnergyDeviceInfo; |
| 18 using device::win::BluetoothLowEnergyServiceInfo; |
| 19 | 19 |
| 20 const char kPlatformNotSupported[] = | 20 const char kPlatformNotSupported[] = |
| 21 "Bluetooth Low energy is only supported on Windows 8 and later."; | 21 "Bluetooth Low energy is only supported on Windows 8 and later."; |
| 22 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; | 22 const char kDeviceEnumError[] = "Error enumerating Bluetooth LE devices."; |
| 23 const char kDeviceInfoError[] = | 23 const char kDeviceInfoError[] = |
| 24 "Error retrieving Bluetooth LE device information."; | 24 "Error retrieving Bluetooth LE device information."; |
| 25 const char kDeviceAddressError[] = | 25 const char kDeviceAddressError[] = |
| 26 "Device instance ID value does not seem to contain a Bluetooth Adapter " | 26 "Device instance ID value does not seem to contain a Bluetooth Adapter " |
| 27 "address."; | 27 "address."; |
| 28 const char kDeviceFriendlyNameError[] = "Device name is not valid."; | 28 const char kDeviceFriendlyNameError[] = "Device name is not valid."; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 | 102 |
| 103 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); | 103 HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); |
| 104 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { | 104 if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) { |
| 105 *error = FormatBluetoothError(message, hr); | 105 *error = FormatBluetoothError(message, hr); |
| 106 return false; | 106 return false; |
| 107 } | 107 } |
| 108 | 108 |
| 109 return true; | 109 return true; |
| 110 } | 110 } |
| 111 | 111 |
| 112 bool CheckSuccess(HRESULT hr, const char* message, std::string* error) { | 112 bool CheckHResult(HRESULT hr, const char* message, std::string* error) { |
| 113 if (FAILED(hr)) { | 113 if (FAILED(hr)) { |
| 114 *error = FormatBluetoothError(message, hr); | 114 *error = FormatBluetoothError(message, hr); |
| 115 return false; | 115 return false; |
| 116 } | 116 } |
| 117 | 117 |
| 118 return true; | 118 return true; |
| 119 } | 119 } |
| 120 | 120 |
| 121 bool CheckSuccess(bool success, const char* message, std::string* error) { |
| 122 if (!success) { |
| 123 CheckHResult(HRESULT_FROM_WIN32(GetLastError()), message, error); |
| 124 return false; |
| 125 } |
| 126 |
| 127 return true; |
| 128 } |
| 129 |
| 130 bool CheckNoData(HRESULT hr, size_t length) { |
| 131 if (hr == HRESULT_FROM_WIN32(ERROR_NOT_FOUND)) |
| 132 return true; |
| 133 |
| 134 if (SUCCEEDED(hr) && length == 0) |
| 135 return true; |
| 136 |
| 137 return false; |
| 138 } |
| 139 |
| 140 bool CheckMoreData(HRESULT hr, const char* message, std::string* error) { |
| 141 if (SUCCEEDED(hr)) { |
| 142 *error = FormatBluetoothError(message, hr); |
| 143 return false; |
| 144 } |
| 145 |
| 146 if (hr != HRESULT_FROM_WIN32(ERROR_MORE_DATA)) { |
| 147 *error = FormatBluetoothError(message, hr); |
| 148 return false; |
| 149 } |
| 150 |
| 151 return true; |
| 152 } |
| 153 |
| 121 bool CheckExpectedLength(size_t actual_length, | 154 bool CheckExpectedLength(size_t actual_length, |
| 122 size_t expected_length, | 155 size_t expected_length, |
| 123 const char* message, | 156 const char* message, |
| 124 std::string* error) { | 157 std::string* error) { |
| 125 if (actual_length != expected_length) { | 158 if (actual_length != expected_length) { |
| 126 *error = FormatBluetoothError(message, E_FAIL); | 159 *error = FormatBluetoothError(message, E_FAIL); |
| 127 return false; | 160 return false; |
| 128 } | 161 } |
| 129 | 162 |
| 130 return true; | 163 return true; |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 } | 269 } |
| 237 | 270 |
| 238 if (actual_length >= 1) { | 271 if (actual_length >= 1) { |
| 239 // Ensure string is zero terminated. | 272 // Ensure string is zero terminated. |
| 240 instance_id.get()[actual_length - 1] = 0; | 273 instance_id.get()[actual_length - 1] = 0; |
| 241 device_info->id = base::SysWideToUTF8(instance_id.get()); | 274 device_info->id = base::SysWideToUTF8(instance_id.get()); |
| 242 } | 275 } |
| 243 return true; | 276 return true; |
| 244 } | 277 } |
| 245 | 278 |
| 246 bool CollectDeviceFriendlyName( | 279 bool CollectBluetoothLowEnergyDeviceFriendlyName( |
| 247 const ScopedDeviceInfoSetHandle& device_info_handle, | 280 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 248 PSP_DEVINFO_DATA device_info_data, | 281 PSP_DEVINFO_DATA device_info_data, |
| 249 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, | 282 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>& device_info, |
| 250 std::string* error) { | 283 std::string* error) { |
| 251 scoped_ptr<DeviceRegistryPropertyValue> property_value; | 284 scoped_ptr<DeviceRegistryPropertyValue> property_value; |
| 252 if (!CollectBluetoothLowEnergyDeviceRegistryProperty(device_info_handle, | 285 if (!CollectBluetoothLowEnergyDeviceRegistryProperty(device_info_handle, |
| 253 device_info_data, | 286 device_info_data, |
| 254 SPDRP_FRIENDLYNAME, | 287 SPDRP_FRIENDLYNAME, |
| 255 &property_value, | 288 &property_value, |
| 256 error)) { | 289 error)) { |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 323 | 356 |
| 324 device_info->connected = !(value->AsUint32() & DN_DEVICE_DISCONNECTED); | 357 device_info->connected = !(value->AsUint32() & DN_DEVICE_DISCONNECTED); |
| 325 // Windows 8 exposes BLE devices only if they are visible and paired. This | 358 // Windows 8 exposes BLE devices only if they are visible and paired. This |
| 326 // might change in the future if Windows offers a public API for discovering | 359 // might change in the future if Windows offers a public API for discovering |
| 327 // and pairing BLE devices. | 360 // and pairing BLE devices. |
| 328 device_info->visible = true; | 361 device_info->visible = true; |
| 329 device_info->authenticated = true; | 362 device_info->authenticated = true; |
| 330 return true; | 363 return true; |
| 331 } | 364 } |
| 332 | 365 |
| 366 bool CollectBluetoothLowEnergyDeviceServices( |
| 367 const base::FilePath& device_path, |
| 368 ScopedVector<BluetoothLowEnergyServiceInfo>* services, |
| 369 std::string* error) { |
| 370 base::File file(device_path, base::File::FLAG_OPEN | base::File::FLAG_READ); |
| 371 if (!file.IsValid()) { |
| 372 *error = file.ErrorToString(file.error_details()); |
| 373 return false; |
| 374 } |
| 375 |
| 376 USHORT required_length; |
| 377 HRESULT hr = BluetoothGATTGetServices(file.GetPlatformFile(), |
| 378 0, |
| 379 NULL, |
| 380 &required_length, |
| 381 BLUETOOTH_GATT_FLAG_NONE); |
| 382 if (CheckNoData(hr, required_length)) |
| 383 return true; |
| 384 if (!CheckMoreData(hr, kDeviceInfoError, error)) |
| 385 return false; |
| 386 |
| 387 scoped_ptr<BTH_LE_GATT_SERVICE[]> gatt_services( |
| 388 new BTH_LE_GATT_SERVICE[required_length]); |
| 389 USHORT actual_length = required_length; |
| 390 hr = BluetoothGATTGetServices(file.GetPlatformFile(), |
| 391 actual_length, |
| 392 gatt_services.get(), |
| 393 &required_length, |
| 394 BLUETOOTH_GATT_FLAG_NONE); |
| 395 if (!CheckHResult(hr, kDeviceInfoError, error)) |
| 396 return false; |
| 397 if (!CheckExpectedLength( |
| 398 actual_length, required_length, kDeviceInfoError, error)) { |
| 399 return false; |
| 400 } |
| 401 |
| 402 for (USHORT i = 0; i < actual_length; ++i) { |
| 403 BTH_LE_GATT_SERVICE& gatt_service(gatt_services.get()[i]); |
| 404 BluetoothLowEnergyServiceInfo* service_info = |
| 405 new BluetoothLowEnergyServiceInfo(); |
| 406 service_info->uuid = gatt_service.ServiceUuid; |
| 407 services->push_back(service_info); |
| 408 } |
| 409 |
| 410 return true; |
| 411 } |
| 412 |
| 333 bool CollectBluetoothLowEnergyDeviceInfo( | 413 bool CollectBluetoothLowEnergyDeviceInfo( |
| 334 const ScopedDeviceInfoSetHandle& device_info_handle, | 414 const ScopedDeviceInfoSetHandle& device_info_handle, |
| 335 PSP_DEVICE_INTERFACE_DATA device_interface_data, | 415 PSP_DEVICE_INTERFACE_DATA device_interface_data, |
| 336 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, | 416 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo>* device_info, |
| 337 std::string* error) { | 417 std::string* error) { |
| 338 // Retrieve required # of bytes for interface details | 418 // Retrieve required # of bytes for interface details |
| 339 ULONG required_length = 0; | 419 ULONG required_length = 0; |
| 340 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, | 420 BOOL success = SetupDiGetDeviceInterfaceDetail(device_info_handle, |
| 341 device_interface_data, | 421 device_interface_data, |
| 342 NULL, | 422 NULL, |
| (...skipping 29 matching lines...) Expand all Loading... |
| 372 } | 452 } |
| 373 | 453 |
| 374 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( | 454 scoped_ptr<device::win::BluetoothLowEnergyDeviceInfo> result( |
| 375 new device::win::BluetoothLowEnergyDeviceInfo()); | 455 new device::win::BluetoothLowEnergyDeviceInfo()); |
| 376 result->path = | 456 result->path = |
| 377 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); | 457 base::FilePath(std::wstring(device_interface_detail_data->DevicePath)); |
| 378 if (!CollectBluetoothLowEnergyDeviceInstanceId( | 458 if (!CollectBluetoothLowEnergyDeviceInstanceId( |
| 379 device_info_handle, &device_info_data, result, error)) { | 459 device_info_handle, &device_info_data, result, error)) { |
| 380 return false; | 460 return false; |
| 381 } | 461 } |
| 382 if (!CollectDeviceFriendlyName( | 462 if (!CollectBluetoothLowEnergyDeviceFriendlyName( |
| 383 device_info_handle, &device_info_data, result, error)) { | 463 device_info_handle, &device_info_data, result, error)) { |
| 384 return false; | 464 return false; |
| 385 } | 465 } |
| 386 if (!CollectBluetoothLowEnergyDeviceAddress( | 466 if (!CollectBluetoothLowEnergyDeviceAddress( |
| 387 device_info_handle, &device_info_data, result, error)) { | 467 device_info_handle, &device_info_data, result, error)) { |
| 388 return false; | 468 return false; |
| 389 } | 469 } |
| 390 if (!CollectBluetoothLowEnergyDeviceStatus( | 470 if (!CollectBluetoothLowEnergyDeviceStatus( |
| 391 device_info_handle, &device_info_data, result, error)) { | 471 device_info_handle, &device_info_data, result, error)) { |
| 392 return false; | 472 return false; |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 516 value_(value.Pass()), | 596 value_(value.Pass()), |
| 517 value_size_(value_size) { | 597 value_size_(value_size) { |
| 518 } | 598 } |
| 519 | 599 |
| 520 uint32_t DevicePropertyValue::AsUint32() const { | 600 uint32_t DevicePropertyValue::AsUint32() const { |
| 521 CHECK_EQ(property_type_, static_cast<DEVPROPTYPE>(DEVPROP_TYPE_UINT32)); | 601 CHECK_EQ(property_type_, static_cast<DEVPROPTYPE>(DEVPROP_TYPE_UINT32)); |
| 522 CHECK_EQ(value_size_, sizeof(uint32_t)); | 602 CHECK_EQ(value_size_, sizeof(uint32_t)); |
| 523 return *reinterpret_cast<uint32_t*>(value_.get()); | 603 return *reinterpret_cast<uint32_t*>(value_.get()); |
| 524 } | 604 } |
| 525 | 605 |
| 606 BluetoothLowEnergyServiceInfo::BluetoothLowEnergyServiceInfo() { |
| 607 } |
| 608 |
| 609 BluetoothLowEnergyServiceInfo::~BluetoothLowEnergyServiceInfo() { |
| 610 } |
| 611 |
| 526 BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() | 612 BluetoothLowEnergyDeviceInfo::BluetoothLowEnergyDeviceInfo() |
| 527 : visible(false), authenticated(false), connected(false) { | 613 : visible(false), authenticated(false), connected(false) { |
| 528 address.ullLong = BLUETOOTH_NULL_ADDRESS; | 614 address.ullLong = BLUETOOTH_NULL_ADDRESS; |
| 529 } | 615 } |
| 530 | 616 |
| 531 BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { | 617 BluetoothLowEnergyDeviceInfo::~BluetoothLowEnergyDeviceInfo() { |
| 532 } | 618 } |
| 533 | 619 |
| 534 bool IsBluetoothLowEnergySupported() { | 620 bool IsBluetoothLowEnergySupported() { |
| 535 return base::win::GetVersion() >= base::win::VERSION_WIN8; | 621 return base::win::GetVersion() >= base::win::VERSION_WIN8; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 558 case kNoMoreDevices: | 644 case kNoMoreDevices: |
| 559 return true; | 645 return true; |
| 560 case kError: | 646 case kError: |
| 561 return false; | 647 return false; |
| 562 case kOk: | 648 case kOk: |
| 563 devices->push_back(device_info.release()); | 649 devices->push_back(device_info.release()); |
| 564 } | 650 } |
| 565 } | 651 } |
| 566 } | 652 } |
| 567 | 653 |
| 654 bool EnumerateKnownBluetoothLowEnergyServices( |
| 655 BluetoothLowEnergyDeviceInfo* device_info, |
| 656 ScopedVector<BluetoothLowEnergyServiceInfo>* services, |
| 657 std::string* error) { |
| 658 return CollectBluetoothLowEnergyDeviceServices( |
| 659 device_info->path, services, error); |
| 660 } |
| 661 |
| 568 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( | 662 bool ExtractBluetoothAddressFromDeviceInstanceIdForTesting( |
| 569 const std::string& instance_id, | 663 const std::string& instance_id, |
| 570 BLUETOOTH_ADDRESS* btha, | 664 BLUETOOTH_ADDRESS* btha, |
| 571 std::string* error) { | 665 std::string* error) { |
| 572 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); | 666 return ExtractBluetoothAddressFromDeviceInstanceId(instance_id, btha, error); |
| 573 } | 667 } |
| 574 | 668 |
| 575 } // namespace win | 669 } // namespace win |
| 576 } // namespace device | 670 } // namespace device |
| OLD | NEW |